• Spring中@Autowired注解装配流程


    众所周知,Autowired注解是通过AutowiredAnnotationBeanPostProcessor来解析的

    第一个问题

    注册AutowiredAnnotationBeanPostProcessor

    AutowiredAnnotationBeanPostProcessor在哪里注册的?

    过程比较复杂,在使用xml和注解不同的场景中,略有不同,具体可以参考如下文章:

    xml开发方式下AutowiredAnnotationBeanPostProcessor的注册时机https://blog.csdn.net/leisure_life/article/details/125570942?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22125570942%22%2C%22source%22%3A%22leisure_life%22%7D&ctrtid=u1pD4

    注解开发方式下AutowiredAnnotationBeanPostProcessor的注册时机https://blog.csdn.net/leisure_life/article/details/125572151?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22125572151%22%2C%22source%22%3A%22leisure_life%22%7D&ctrtid=ifvaE

    只是注册了,只是在beanDefinitionMap中有了org.springframework.context.annotation.internalAutowiredAnnotationProcessor元素而已,还没创建成AutowiredAnnotationBeanPostProcessor对象

     此时的beanFactory的 singletonObjets中空空如也,也印证着确实没有AutowiredAnnotationBeanPostProcessor对象的存在

    故而,引出第二个问题

    实例化AutowiredAnnotationBeanPostProcessor

    经过debug得知,AutowiredAnnotationBeanPostProcessor是在registerBeanPostProcessors(beanFactory)这一步实例化的

     看一下详细过程

    registerBeanPostProcessors

    1. /**
    2. * Instantiate and register all BeanPostProcessor beans,
    3. * respecting explicit order if given.
    4. * <p>Must be called before any instantiation of application beans.
    5. */
    6. protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    7. PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
    8. }

    代码上的注释明白的写着,实例化和注册所有的BeanPostProcessor

    进去 registerBeanPostProcessors后,一上来就是getBeanNamesForType,把类型是BeanPostProcessor.class的bean的名称都从容器获取出来

    可以看到postProcessorNames有三个元素,internalAutowiredAnnotationProcessor赫然在列

     拿到postProcessorNames后,循环遍历,进行getBean操作

    BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);

    里面有个小细节,getBean前还有一个if判断

    if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) 

    判断这个BeanPostProcessor是否是PriorityOrdered类型

     查看一下类图AutowiredAnnotationBeanPostProcessor,是实现了PriorityOrdered接口的

     所以能顺理成章的进入getBean环节,后面的就是熟悉的流程了,getBean调用doGetBean,doGetBean会先调用getSingleton(beanName)在容器中找一下,找到就返回,这里肯定是没有的

    没找到就继续调用createBean,doCreateBean,

     然后调到createBeanInstance,instantiateBean

     跟踪到最后,发现是用java的发射方式,生成了一个对象返回的

     

     至此,AutowiredAnnotationBeanPostProcessor就被创建出来了

     如果要简短一点概括,就是在执行refresh方法的registerBeanPostProcessors方法中,进行实例化的。

    然后AutowiredAnnotationBeanPostProcessor的实例化就完成了,然后就引出了第三个问题,在哪调用的?

    实例化和初始化

    要深刻理解@Autowired,需要先掌握一个前置知识,就是spring对象的完整创建过程分为两步,实例化和初始化,这个和jvm的实例化初始化稍有不同,spring中的实例化只的是“半成品”对象,里面的属性还未完成赋值,而初始化就可以理解为完整的对象,里面的所有属性都完成了赋值。

    多提一嘴,正是因为有了分两步创建对象的策略,循环依赖问题才可以得以解决,这是后话,改天单独分析。

    执行AutowiredAnnotationBeanPostProcessor

    严格的来说不是执行AutowiredAnnotationBeanPostProcessor,而是执行AutowiredAnnotationBeanPostProcessor类中的postProcessMergedBeanDefinition方法

    这个过程发生在bean的创建过程中,当bean完成了实例化(还未完成初始化)时,会执行一个叫applyMergedBeanDefinitionPostProcessors的方法,对@Autowired进行预解析

    预解析

    预解析就是,识别被@Autowired标注了的属性、构造方法、方法等,并将上面的注解元数据信息缓存起来

    我们可看到,这里循环调用的执行的是 MergedBeanDefinitionPostProcessor,咋一看这和我们的主角AutowiredAnnotationBeanPostProcessor毫无关系,怎么就会执行呢

    这就要回到我们的 AutowiredAnnotationBeanPostProcessor类结构,可以看到不仅它实现了MergedBeanDefinitionPostProcessor接口,还实现了SmartInstantiationAwareBeanPostProcessor接口,所以这里是会执行的

    写个小案例,Teacher中用@Autowired注入了Student

     可以看到,在Teacher完成了实例化,并未完成初始化时,student的值还是null

     值此“半成品”之际,applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName)被执行,FactoryBean里面实现了MergedBeanDefinitionPostProcessor的BeanPostProcessor有多个,我们只关心AutowiredAnnotationBeanPostProcessor这个

     

     findAutowiringMetadata,查找Autowired元数据

     查找的细节就不深究了,总之,最终找到了student这个注解元数据,并且结果放到了injectionMetadataCache中。

     值此,预解析完成。

    真正的解析

    在完成与解析之后,我们的Teacher对象还只是完成了实例化,还没有完成初始化,需要调用populateBean 进行属性的填充,@Autowired真正的解析就发生在这里

    populateBean

    在populateBean中,主要是执行InstantiationAwareBeanPostProcessor的postProcessProperties方法进行属性的注入,和上面的一样,也是因为AutowiredAnnotationBeanPostProcessor间接的实现了InstantiationAwareBeanPostProcessor,所以才得以执行

     我们进去看看postProcessProperties方法

    先从预解析步骤已经解析了并缓存了的缓存中取出注解元数据

     然后的核心就是

    metadata.inject(bean, beanName, pvs);

    从缓存中取出所有需要注入的 元素,这里只有一个student,调用element.inject

    inject拿到student这个字段,检查是否已经处理过,没处理就要解析字段值

     resolveFieldValue的过程非常复杂,复杂到我目前还没有整明白

    总之,通过resolveFieldValue,返回了student的对象

    然后通过反射方式field.set(bean, value)将student设置给Teacher对象,完成了我们的注入

    后续继续执行initializeBean等方法,Teacher就算真正的完成创建了。

    总结

    总结一下Spring中@Autowired注解装配的大体流程:

    1. 创建容器后都会通过AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)方法将一系列的internalXXXProcessor注册到容器,其中就包括internalAutowiredAnnotationProcessor
    2. 在执行registerBeanPostProcessors(beanFactory)时完成了AutowiredAnnotationBeanPostProcessor的创建与注册
    3. 在用户bean创建过程中(doCreateBean),实例化(createBeanInstance)之后,通过执行applyMergedBeanDefinitionPostProcessors方法,实现@Autowired注解元数据的预解析
    4. 在进行属性填充(populateBean)的过程中,通过调用InstantiationAwareBeanPostProcessor的postProcessProperties方法,在里面执行 inject 完成真正的注入

    后续有空,在深入分析inject里面的逻辑,其中就包含经典面试题——autowired自动装配的两种方式:byName和byType的区别。

  • 相关阅读:
    全志R128应用开发案例——点亮一颗 LED 灯
    Git分布式版本控制工具(二)
    OSG第三方库编译之三十六:Protobuf编译(Windows、Linux、Macos环境下编译)
    企业自建应用对接企业微信发送消息接口
    数据结构-哈希表
    【JS】await异常捕获,这样做才完美
    用go实现cors中间件
    pandas入门 数据结构
    IDEA 集成 Git
    CMake编译 oss -cpp-sdk arm列子
  • 原文地址:https://blog.csdn.net/leisure_life/article/details/125570866