java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > @Autowired依赖注入的原理

基于@Autowired依赖注入的原理分析

作者:找不到、了

这篇文章主要介绍了基于@Autowired依赖注入的原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

@Autowired 是 Spring 框架中的一个注解,用于自动注入依赖。

在 Spring 中,依赖注入(Dependency Injection, DI)是一种设计模式,允许在运行时将对象的依赖关系(即所需的其他对象)自动提供给它,而不是在代码中手动创建依赖对象。

1、介绍

以下为注解的结构图

该注解支持标注在字段、构造函数、方法以及参数上。

注意:

其中的关键属性 required 默认值为 true,表示如果没有合适的 Bean 可以注入,则会抛出异常。required 如果为false的时候,表示可以暂时不实例化。

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    boolean required() default true;
}

2、实现原理

1、扫描及注册 Bean

Spring 在启动时会扫描配置的包,找到被@Compoent、@Service、@Repository和@Controller等注解标记的类,并将它们注册为 Spring 容器中的 Beans。

2、解析依赖

当 Spring 创建一个 Bean 时,它会检查该 Bean 的构造函数、方法或字段中是否有@Autowired注解。

这个注解表明该字段、构造函数或方法是需要进行依赖注入的。

3、类型匹配

Spring 会根据变量的类型去容器中查找匹配的 Bean,默认情况下,Spring 使用的是按类型自动装配。

3、使用场景

3.1、背景

当 Spring 容器检测到有多个同类型的 Bean 可供注入时,默认的行为是抛出 NoUniqueBeanDefinitionException 异常。

3.2、处理方式

1、@Qualifier

如果有多个相同类型的 Bean 时,可以使用 @Qualifier 注解来明确指定要注入的 Bean。

代码示例:

@Autowired
@Qualifier("specificBeanName")
private MyService myService;

2、@Primary注解

1、目的

主要目的是在 Spring 容器中有多个相同类型的 Bean 存在时,提供一种机制来指定哪个 Bean 应该被优先考虑作为默认注入的目标。

2、原理

如果其中一个 Bean 被标记为 @Primary,那么 Spring 将会选择它作为首选项并完成注入过程。

此逻辑发生在 Spring 的自动装配阶段,在这一阶段,容器会评估所有可用的候选 Bean,并根据各种规则(如 @Primary@Qualifier 等)做出最终决策

3、示例

@Configuration
public class AppConfig {

    @Bean
    @Primary
    public MyService primaryMyService() {
        return new MyServiceImpl1();
    }

    @Bean
    public MyService secondaryMyService() {
        return new MyServiceImpl2();
    }
}

在这个配置文件中,我们有两个实现了 MyService接口的服务类——MyServiceImpl1 和 MyServiceImpl2。由于我们在第一个服务实现上加了 @Primary 注解,因此无论何时需要注入 MyService类型的对象,都会优先选取 MyServiceImpl1 实例。

3.3、替代方式

1. @Inject

@Inject 是 Java EE 提供的标准注解,也可以在 Spring 中使用。

它的功能类似于@Autowired,但语义更加清晰,因为它仅关注依赖注入本身而不涉及 Spring 特定的功能。

public class ExampleService {
    private final AnotherService anotherService;

    @Inject
    public ExampleService(AnotherService anotherService) {
        this.anotherService = anotherService;
    }
}

2. 构造函数注入

这种方式被认为是最佳实践之一,尤其适用于强制性依赖项。相比于字段注入或 setter 方法注入,构造函数注入能更好地满足不可变性和测试需求。

示例:

public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) { // 构造函数注入
        this.userRepository = userRepository;
    }
}

3. @Resource

@Resource 是 JNDI 规范的一部分,通常基于名称匹配来查找目标 Bean。

如果没有找到与名字完全一致的 Bean,则会退回到按类型匹配的方式。相比 @Autowired 更加灵活,因为可以直接指定要注入的具体资源名。

示例:

public class MovieRecommender {
    @Resource(name="mainDataSource") // 明确指定了数据源的名字
    DataSource dataSource;
    
    public void recommend() {}
}

4、总结

通俗讲解

把@Autowired看成是一种“智能化的手”。当你需要一个助手(依赖对象)来完成某个任务时,你不需要去亲自找寻和雇佣这个助手,Spring 就像一个高效的秘书,知道你需要什么助手,会自动给你安排好。

你只需要告诉 Spring 你需要的助手的类型,它就会负责寻找并提供给你,而不需要你关心具体的细节。

这样做的好处是可以降低代码的耦合度,让程序的各个部分更容易进行单元测试和维护。只要我们在代码中声明需要的依赖,Spring 就会负责去处理这些依赖,让开发者能更专注于业务逻辑的实现。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文