Spring IoC源码学习:@Autowire 详解

这篇文章详细探讨了Spring框架中@Autowired注解的使用和源码解析,包括如何开启注解配置、构造函数和属性注入的过程。重点分析了AutowiredAnnotationBeanPostProcessor类的职责,从构造函数注入的determineCandidateConstructors方法到属性注入的postProcessMergedBeanDefinition和postProcessPropertyValues方法,揭示了Spring IoC容器如何处理自动装配。
摘要由CSDN通过智能技术生成

微信搜索【程序员囧辉】,关注这个坚持分享技术干货的程序员。

目录

Spring IoC源码学习全系列

前言

如何使用

1.开启注解配置

2.在代码中使用

继承结构

源码解析

AutowiredAnnotationBeanPostProcessor 何时被注册到 BeanFactory?

AnnotationConfigUtils#registerAnnotationConfigProcessors

构造函数注入时做了什么

AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors

代码块1:findAutowiredAnnotation

属性注入时做了什么

1.postProcessMergedBeanDefinition 方法介绍

AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition

代码块2:findAutowiringMetadata

代码块3:buildAutowiringMetadata

代码块4:checkConfigMembers

2.postProcessPropertyValues 方法介绍

AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues 

代码块5:inject

代码块6:AutowiredFieldElement#inject

代码块7:registerDependentBeans

总结

相关文章


Spring IoC源码学习全系列

小白也看得懂的 Spring IoC 核心流程介绍

Spring IoC源码学习:总览

Spring IoC源码学习:ApplicationContext 刷新前的配置

Spring IoC源码学习:obtainFreshBeanFactory详解

Spring IoC源码学习:parseDefaultElement详解

Spring IoC源码学习:parseCustomElement详解

Spring IoC源码学习:context:component-scan 节点详解

Spring IoC源码学习:invokeBeanFactoryPostProcessors详解

Spring IoC源码学习:registerBeanPostProcessors详解

Spring IoC源码学习:finishBeanFactoryInitialization详解

Spring IoC源码学习:getBean详解

Spring IoC源码学习:createBean详解(上)

Spring IoC源码学习:createBean详解(下)

Spring IoC源码学习:@Autowire 详解

Spring IoC源码学习:finishRefresh 详解

 

前言

在 Spring IoC:createBean 详解(上)代码块4.5 和 Spring IoC:createBean详解(下)代码块1代码块4的 7.1.1 我们遗留了一个解析——@Autowire 注解的解析。之所以单独提出来,是因为在我现在接触的项目中,使用 @Autowire 注解的比例非常高,可以说基本用过 Spring 的同学都接触过这个注解,重要性不言而喻。因此,单独拿出来,较详细的介绍一下。

本文只会单独介绍 @Autowire 的部分内容,具体 @Autowire 注解的完整过程,需要结合 Spring IoC:createBean 详解(上)代码块4.5 和 Spring IoC:createBean详解(下)代码块1代码块4的 7.1.1 去看。

 

如何使用

1.开启注解配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"

       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-3.1.xsd">
    <!-- component-scan包含了annotation-config的效果 -->
    <context:component-scan base-package="com.joonwhee.open.demo.service"/>
    <context:annotation-config/>
</beans>

要使用 @Autowire 注解,可以通过 <context:component-scan /> 或 <context:annotation-config/> 来开启,其中前者是包含了后者的效果的,因此现在一般都使用 <context:component-scan /> 即可。

2.在代码中使用

@Service
public class ConstructorServiceImpl implements ConstructorService {

    // 1.属性注入
    @Autowired
    private UserService userService;

    private final DemoService demoService;

    // 2.构造函数注入
    @Autowired
    public ConstructorServiceImpl(DemoService demoService) {
        this.demoService = demoService;
    }
}

该代码中使用了目前最常见的两种注入方式:1)属性注入;2)构造函数注入。

以我自己为例,我周围最常用的是:属性注入,但是 Spring 团队建议使用的方式是:构造函数注入,当你使用属性注入时,鼠标移到属性上的 @Autowire 就可以看到如下图的提示,并且可以通过快捷键将属性注入直接修改成构造函数注入。

构造函数的常见优点是:

  1. 保证依赖不可变(final 关键字)
  2. 保证依赖不为空(省去了检查)
  3. 以完全初始化的状态返回到客户端(调用)代码
  4. 避免了循环依赖
  5. 提升了代码的可复用性

构造函数的常见缺点是:

  1. 构造函数会有很多参数。
  2. 有些类是需要默认构造函数的,一旦使用构造函数注入,就无法使用默认构造函数。
  3. 这个类里面的有些方法并不需要用到这些依赖。

这些优点我看了下,个人觉得还好,只要不瞎用,其实使用属性注入并不会有什么问题。至于使用哪一种,就看个人喜好了。

 

继承结构

@Autowire 注解的功能实现都是由 AutowiredAnnotationBeanPostProcessor 实现,AutowiredAnnotationBeanPostProcessor 的继承关系如下图:

 

源码解析

AutowiredAnnotationBeanPostProcessor 何时被注册到 BeanFactory?

在 Spring IoC:context:component-scan节点详解 中的代码块17就有 AutowiredAnnotationBeanPostProcessor 被注册到 BeanFactory 的代码,如下:

 

AnnotationConfigUtils#registerAnnotationConfigProcessors

查看该方法的上下文,请参考:Spring IoC:context:component-scan节点详解 中的代码块17

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
        BeanDefinitionRegistry registry, Object source) {

    DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    if (beanFactory != null) {
        if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
            // 1.设置dependencyComparator属性
            beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
        }
        if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
            // 2.设置autowireCandidateResolver属性(设置自动注入候选对象的解析器,用于判断BeanDefinition是否为候选对象)
            beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        }
    }

    Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);

    // 3.注册内部管理的用于处理@Configuration注解的后置处理器的bean
    if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
        def.setSource(source);
        // 3.1 registerPostProcessor: 注册BeanDefini
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员囧辉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值