基于@Autowired依赖注入的原理分析
目录
- 1、介绍
- 2、实现原理
- 1、扫描及注册 Bean
- 2、解析依赖
- 3、类型匹配
- 3、使用场景
- 3.1、背景
- 3.2、处理方式
- 1、@Qualifier
- 2、@Primary注解
- 3.3、替代方式
- 1. @Inject
- 2. 构造函数注入
- 3. @Resource
- 4、总结
@Autowired 是 Spring 框架中的一个注解,用于自动注入依赖。
在 Spring 中miRbpBQx,依赖注入(Dependency Injection, DI)是一种设计模式,允许在运行时将对象的依赖关系(即所需的其他对象)自动提供给它,而不是在代码中手动创建依赖对象。
1、介绍
以下为注解的结构图
该注解支持标注在字段、构造函数、方法以及参数上。
注意:
其中的关键属性 required 默认值为 true
,表示如果没有合适的 Bean 可以注入,则会抛出异常。required 如果为false的时候,表示可以暂时不实例化。
@Target({ElementType.CONSTRUCTOR, Elemehttp://www.devze.comntType.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 使用的是按类型自动装配。
- 如果找到唯一的匹配项,就会将其注入。
- 如果有多个匹配项,Spring 会抛出异常;可以通过设置required
=
false或者使用 @Qualifier或者
@Primary来解决歧义问题。 - 如果没有匹配项,通常会返回 null(前提是字段是可空的)。
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 你需要的助手的类型,它就会负责寻找并提供给你,而不需要你关心具体的细节。
这样做的好处是可以降低代码的耦合度,让程序的各个部分更容易进行单元测试和维护python。只要我们在代码中声明需要的依赖,Spring 就会负责去处理这些依赖,让开发者能更专注于业务逻辑的实现。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。
精彩评论