当前位置: 首页 > article >正文

Spring IoC DI 之 属性注入

 一、DI (依赖注入)

依赖注入(DI)是一种实现控制反转(IoC)的技术,可以在运行时动态地向应用程序提供其所需的依赖。在 Spring 框架中,DI 是一种常用的实践,有助于提高代码的模块化和灵活性。下面是依赖注入的一些关键点和优势:

依赖注入的工作原理
  1. 容器管理

    • 在 Spring 中,容器负责创建和管理对象(即 Beans)。开发者只需要通过配置(可以是 XML 文件、注解或 Java 配置类)指定依赖关系。
  2. 注入方式

    • 构造器注入:通过构造函数传递依赖。
    • 设置器注入:通过 JavaBean 属性的 setter 方法传递依赖。
    • 字段注入:直接在字段上注入依赖,通常使用 @Autowired 注解。
  3. 运行时绑定

    • 依赖注入是在运行时处理的,这意味着应用程序的组件可以在不修改代码的情况下,通过更改配置来使用不同的依赖实现。

二、使用 字段注入自动注入 Bean

在 Spring 的组件(如由 @Component, @Service, @Controller 等注解标记的类)中,你可以使用 @Autowired 注解自动注入 Bean。这是推荐的方法,因为它减少了对 Spring API 的直接依赖,并且使得代码更加简洁。

@Component
public class UserService {
    @Autowired
    private User user;

    public void displayUser() {
        System.out.println("User Name: " + user.getName());
    }
}

Spring 应用中使用 @Autowired 注解自动注入 Bean 且存在多个相同类型的 Bean 时,会出现冲突,因为 Spring 不知道应该注入哪一个。为了解决这个问题,Spring 提供了几种方法来指定要注入的具体 Bean,确保准确性和灵活性。

1)指定Bean 注入
a) 使用 @Qualifier 注解

@Qualifier 注解用来进一步细化 @Autowired 的注入选择。通过为每个 Bean 定义一个名称,然后在注入时指定这个名称,可以控制哪一个 Bean 被注入。

@Component
public class VehicleService {
    @Autowired
    @Qualifier("car")
    private Vehicle vehicle;

    public void service() {
        vehicle.performService();
    }
}

@Component("car")
public class Car implements Vehicle {
    @Override
    public void performService() {
        System.out.println("Servicing a car");
    }
}

@Component("bike")
public class Bike implements Vehicle {
    @Override
    public void performService() {
        System.out.println("Servicing a bike");
    }
}

在这个例子中,我们有两个 Vehicle 类型的 Bean,分别是 CarBike。使用 @Qualifier("car") 告诉 Spring 在注入 Vehicle 类型的依赖时使用名为 "car" 的 Bean 

b)  使用 @Primary 注解

当你想要在多个相同类型的 Bean 中指定一个“默认”Bean 时,可以使用 @Primary 注解。当存在多个 Bean 且其中一个被标记为 @Primary,Spring 会优先注入这个 Bean。

@Component
@Primary
public class Car implements Vehicle {
    @Override
    public void performService() {
        System.out.println("Servicing a car");
    }
}

@Component
public class Bike implements Vehicle {
    @Override
    public void performService() {
        System.out.println("Servicing a bike");
    }
}

@Component
public class VehicleService {
    @Autowired
    private Vehicle vehicle;  // 默认注入 @Primary 标记的 Bean

    public void service() {
        vehicle.performService();
    }
}

在这个例子中,Car 类被标记为 @Primary,因此它会被默认注入到 VehicleService 中,除非使用 @Qualifier 明确指定其他 Bean。

c)  使用特定方法命名或 @Bean 注解中的名称

在 Java 配置类中,你可以通过方法名称或在 @Bean 注解中指定名称来控制 Bean 的标识符。然后,可以结合使用 @Autowired@Qualifier

@Configuration
public class AppConfig {
    @Bean(name = "car")
    public Vehicle car() {
        return new Car();
    }

    @Bean(name = "bike")
    public Vehicle bike() {
        return new Bike();
    }
}

然后,使用 @Qualifier 来指定注入哪一个。

通过这些方法,你可以在 Spring 中精确控制哪个 Bean 被注入到有多个相同类型的 Bean 的情况下,从而保证应用的正确性和灵活性。

2)使用 @Resource 或 @Inject 注解

@Resource@Inject 是 JSR-250 和 JSR-330 的标准 Java 注解,分别来自 Java EE 和依赖注入规范。它们与 @Autowired 类似,但略有不同的注入语义和配置方式。

示例代码(使用 @Resource):

@Component
public class UserService {
    @Resource(name="user")
    private User user;

    public void displayUser() {
        System.out.println("User Name: " + user.getName());
    }
}

三、  构造方法注入

这种方式是最推荐的,因为它确保了所有的依赖在对象被创建之前就已经准备好了。

@Component
public class UserService {
    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void performAction() {
        System.out.println("Action performed with user repository.");
    }
}

四、Setter 方法注入

这种方法适用于可选依赖,或者在对象创建之后还可以更改依赖的情况

@Component
public class NotificationService {
    private EmailService emailService;

    @Autowired
    public void setEmailService(EmailService emailService) {
        this.emailService = emailService;
    }

    public void sendNotification(String message, String recipient) {
        emailService.sendEmail(message, recipient);
    }
}

@Component
public class EmailService {
    public void sendEmail(String message, String recipient) {
        System.out.println("Email sent to " + recipient + " with message: " + message);
    }
}


http://www.kler.cn/news/319810.html

相关文章:

  • BottomNavigationView 添加角标
  • c++开发实战之网络编程(一)
  • 三维重建的几何评价指标
  • 面试算法题精讲:求数组两组数差值和的最大值
  • 只出现一次的数字 II
  • Redis:事务
  • Hive 的窗口函数 详解
  • 代码随想录算法训练营| 454.四数相加II 、 383. 赎金信 、 15. 三数之和 、 18. 四数之和
  • 有威胁的武器武装检测系统源码分享
  • WebGL渲染与创建2D内容
  • 树——数据结构
  • 移动端如何实现智能语音交互
  • 【LGR-200-Div.4】洛谷入门赛 #27 A - H题解,包含(C++, Go语言)
  • Mybatis中sql数组为空判断
  • SpringBoot 整合docker,执行容器服务
  • Qt系统相关——事件
  • JavaScript --模版字符串用反引号
  • Qt (19)【Qt 线程安全 | 互斥锁QMutex QMutexLocker | 条件变量 | 信号量】
  • python学习笔记(3)——控制语句
  • Java获取Object中Value的方法
  • 数据结构-3.链表
  • 无人机在隧道中如何实现在无卫星信号下的自主导航
  • 将ipad作为数位板使用教程/出现延迟拖拽怎么办?
  • 在jupyter notebook中取消代理服务器的解决方案
  • 编程遇到问题了?一个命令让 AI 解决你的困惑!
  • Android——内部/外部存储
  • HTTP常见状态码 HTTP的逐步发展(通俗易懂版)
  • 利士策分享,赚钱有道,底线思维不可抛
  • 网络安全-shire写任务计划、反弹shell、写私钥、反序列化
  • 机器学习算法与Python实战 | 三万字详解!GPT-5:你需要知道的一切(上)建议收藏!