• Spring @Autowire注解源码详解


    目录

    一:触发方式:

    二:源码解析

    2.1 扫描注入点

    2.2 属性赋值


    一:触发方式:

    1.Spring容器在每个Bean实例化之后,调用AutowireAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法进行扫描注入点

    2.Spring在每个Bean实例化之后,扫描完注入点之后,调用populateBean进行Bean注入,调用postProcessPropertyValues方法

    二:源码解析

    2.1 扫描注入点

    通过在属性、构造方法、set方法上添加@Autowire注解可以将Bean进行依赖注入

    1. package service;
    2. import org.springframework.beans.factory.annotation.Autowired;
    3. public class UserService1 {
    4. @Autowired
    5. private OrderService orderService;
    6. public void test(){
    7. System.out.println(orderService);
    8. }
    9. }

    首先先查找注入点,在创建Bean时,实例化后,调用

    1. AbstractAutowireCapableBeanFactory.java
    2. protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    3. throws BeanCreationException {
    4. ....
    5. if (!mbd.postProcessed) {
    6. try {
    7. //todo 在实例化后,对MergeBeanDefinition进行属性修改
    8. applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
    9. }
    10. catch (Throwable ex) {
    11. throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    12. "Post-processing of merged bean definition failed", ex);
    13. }
    14. mbd.postProcessed = true;
    15. }
    16. ..
    17. }

    进入applyMergedBeanDefinitionPostProcessors方法中,调用processor.postProcessMergedBeanDefinition(mbd,beanType,beanName);

    1. protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class beanType, String beanName) {
    2. for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {
    3. processor.postProcessMergedBeanDefinition(mbd, beanType, beanName);
    4. }
    5. }

    处理@Autowire注解的类时AutowiredAnnotationBeanPostProcessor

     进入findAutowiringMetadata(beanName,beanType,null);

     

    buildAutowiringMetadata(final Class clazz) 方法中,循环遍历属性和循环遍历方法

    ,其中属性和方法不能是静态的 ,将field和required封装成一个AutowireFieldElement的一项,加入到currElements,最后合并成elements 

     

    以上就是依赖注入寻找注入点的过程,还没进行属性赋值

    2.2 属性赋值

    在Bean的实例化之后,进行循环依赖、属性填充、初始化、销毁bean。

    进入到 populateBean(beanName, mbd, instanceWrapper);

    主要根据postProcessProperties 进行属性注入

    在这里找注入点、属性赋值。查找注入点上面分析过,下面分析属性赋值。

     @Autowire注解加在field上的inject()方法在AutowiredFieldElement内部类中

     第一次没有缓存进入到resolveFieldValue(field,bean,beanName)中,缓存针对于原型bean,因为单例bean只会创建一次,属性也是注入一次。

    最终在DefaultListableBeanFactory.java中 将bean找到返回

    1.首先处理@Value注解

    2.判断是不是Map、List复杂Bean,其中还是调用findAutowireCandidates方法,根据类型去Spring容器中去找

    Map matchingBeans = findAutowireCandidates(beanName, valueType,
          new MultiElementDescriptor(descriptor));

    3.根据类型去Spring容器中找Bean,返回的key为beanName,value有可能是bean对象,有可能是bean class

    Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);

    4.如果matcingbeans.size >1 根据类型找到多个bean时,再根据name去找,调用

    determineAutowireCandidate 方法,先去判断有没有加@primary注解 ,如果有则返回这个bean,然后再判断这个bean的优先级,再匹配descriptor的名字,要么是字段的名字,要么是set方法入参的名字。最终返回这个beanName,如果这些注解都没有加则返回null。
    

    5.如果第四步返回的bull,并且没有配置@Autowire(required=false) 并且 beans不是复杂类型,则抛异常  expected single matching bean but found beanName

    6.根据beanName,获取bean /bean class 返回

     

  • 相关阅读:
    【esp32】 PWM控制LED亮度原理及代码详解
    JAVA【Maven中的核心概念】
    使用HTML CSS制作静态网站【中秋节】
    vant 按需导入 vue2
    无线互动会议室解决方案-总控室部署
    Java【数组】定义与使用,什么是引用类型你知道吗
    Github每日精选(第35期):移动设备数据库Realm
    集合的使用
    PHP实现赛邮【SUBMAIL】短信通知
    go 端口转发 代理V2 --chatGPT
  • 原文地址:https://blog.csdn.net/qq_24186017/article/details/128159912