关于spring:都0202年了还在说springAutowired是byType注入的

30次阅读

共计 5757 个字符,预计需要花费 15 分钟才能阅读完成。

前言

  • 基于上篇文章从源码的角度查找 Spring @Autowired 注解不能依赖注入动态变量的起因的启发,我感觉还有必要再总结下 spring 中 @Autowired 注解的原理。自己在未读 spring 源码时始终认为 @Autowired 的依赖注入模式是byType,直到我看了源码我才突破了这个误区!

一、Spring 依赖注入类型的基础知识

  • 在上篇博客中也有提到,spring 的依赖注入次要蕴含如下几个方面:

    常见依赖注入类型 对应的值 备注
    AbstractBeanDefinition.AUTOWIRE_NO 0 不开启主动拆卸性能
    AbstractBeanDefinition.AUTOWIRE_BY_NAME 1 依据变量名来主动拆卸
    AbstractBeanDefinition.AUTOWIRE_BY_TYPE 2 依据类型主动拆卸
    AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR 3 依据构造方法主动拆卸
    AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT 间接疏忽。。。 源码中提醒在 spring 3.0 之后就弃用了 (具体看上面的源码),所以这里就不列出它具体的原理了( 其实是本人不晓得。。。。)
  • spring 3.0 弃用 AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT 源码

    /**
     * Constant that indicates determining an appropriate autowire strategy
     * through introspection of the bean class.
     * @see #setAutowireMode
     * @deprecated as of Spring 3.0: If you are using mixed autowiring strategies,
     * use annotation-based autowiring for clearer demarcation of autowiring needs.
     */
    @Deprecated
    public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;

二、如何判断一个 bean 的依赖注入类型

  • 步骤如下:

    • 第一:获取到 bean 对应的 BeanDefinition 对象 (能够通过后置处理器(eg: BeanFactoryPostProcessor) 获取 bean 工厂,进而获取到 beanDefinition)
    • 第二:强转成GenericBeanDefinition
    • 第三:调用 getResolvedAutowireMode() 办法
  • 或者间接在 populateBean() 办法中进行断点调试,这里我抉择断点调试,废话不多说,上我的项目证实!

三、我的项目测试

3.1 我的项目预览

  • AppConfig.java

    @Configuration
    @ComponentScan("com.eugene.sumarry.csdn.autowired")
    public class AppConfig {}
  • Entry.java

    public class Entry {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    
            System.out.println(context.getBean(UserService.class));
    
        }
    }
  • UserService.java

    @Service
    public class UserService {
    
        @Autowired
        private UserDao userDao;
    
        @Override
        public String toString() {
            return "UserService{" +
                    "userDao=" + userDao +
                    '}';
        }
    }
  • UserDao.java

    @Repository
    public class UserDao {}

3.2 运行测试

spring 会有两个中央实现主动拆卸,:
第一:构造方法主动拆卸
第二:populateBean 办法中进行主动拆卸
咱们本次总结的是 @Autowired 注解,疏忽构造方法局部。接下来,咱们间接运行 main 办法,并定位到 populateBean 办法的要害局部

  • 条件断点调试:

    从上述图中能够看到,从 beanDefinition 中获取的依赖注入的属性为 0, 由上述表格中可知它的值为:AbstractBeanDefinition.AUTOWIRE_NO,其实咱们能够在AbstractBeanDefinition 类中查看 autowireMode 属性,它的默认值就是:AUTOWIRE_NO,如图所示:

,可能有人感觉我在忽悠,之前不是说要通过 getResolvedAutowireMode() 办法来获取么,那咱们再列出下 getResolvedAutowireMode() 的源码

/**
 * Return the resolved autowire code,
 * (resolving AUTOWIRE_AUTODETECT to AUTOWIRE_CONSTRUCTOR or AUTOWIRE_BY_TYPE).
 * @see #AUTOWIRE_AUTODETECT
 * @see #AUTOWIRE_CONSTRUCTOR
 * @see #AUTOWIRE_BY_TYPE
 */
public int getResolvedAutowireMode() {
    // ************* 看这里 **************
    // 用到了上述所说的 autowireMode 属性, 默认值为
    // AUTOWIRE_NO, 所以间接走 else return 了
    if (this.autowireMode == AUTOWIRE_AUTODETECT) {Constructor<?>[] constructors = getBeanClass().getConstructors();
        for (Constructor<?> constructor : constructors) {if (constructor.getParameterCount() == 0) {return AUTOWIRE_BY_TYPE;}
        }
        return AUTOWIRE_CONSTRUCTOR;
    }
    else {return this.autowireMode;}
}
那 `@Autowired` 注解不是 `byType` 来依赖注入的,那它的原理是什么呢?这里还要联合上一篇文章: [从源码的角度查找 Spring @Autowired 注解不能依赖注入动态变量的起因](https://blog.csdn.net/avengerEug/article/details/105860077)的论断。在 spring 外部,`@Autowired` 注解的性能是通过一个叫 **AutowiredAnnotationBeanPostProcessor** 的后置处理器来解决的。上篇文章介绍的是它 **MergedBeanDefinitionPostProcessors** 的身份 (** 就是将以后类及其父类(不蕴含 Object 类) 的所有蕴含 @Autowired 注解的字段和办法以 InjectionMetadata 对象的形式保留在 `injectionMetadataCache` 属性中 **)。在上篇文章中,咱们没有总结 @Autowired 注解的依赖注入逻辑,当初咱们来补上。

四、AutowiredAnnotationBeanPostProcessor 的 InstantiationAwareBeanPostProcessor 身份

  • 是的,你没看错,当初要看 AutowiredAnnotationBeanPostProcessor 的另外一个身份了。咱们回到 populateBean 办法,持续调试代码,如下图所示:

此时咱们跟着断点走,进入到 AutowiredAnnotationBeanPostProcessorpostProcessPropertyValues办法,如下图所示:

咱们继续执行,将断点打到办法的出口处,如下图所示:

综上所述,@Autowired注解的依赖注入就这样实现了 (AutowiredAnnotationBeanPostProcessor 在解决依赖注入时,从 bean 工厂中去获取,首先是依据字段的类型去找符合条件的 bean,若失去的 bean 有多个,则找出有 @Primary 注解润饰的 bean,若都没有,则进化成 @Resource 注解的性能,即依据字段名去寻找 bean,若都没有,则会抛出找到多个 bean 的异样。能够定位到 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject 办法细看注入逻辑)。
这里顺便提一句:不晓得大家看到 本章 (第四章) 第一张图的如下代码没:

for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
        pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
        if (pvs == null) {return;}
    }
}
有一个 `return` 关键字,假如咱们写一个实现了 `InstantiationAwareBeanPostProcessor` 接口的 bean,那么是不是能够毁坏掉 `@Autowired` 注解的性能?当然,这里有个注意事项:` 就是本人写的这个 bean 的解决程序要在 AutowiredAnnotationBeanPostProcessor 后面。`,我本人做了这么个试验,在我的项目中增加了如下代码后,`@Autowired` 注解的性能就生效了(** 我测试的时候尔后置处理器比 AutowiredAnnotationBeanPostProcessor 先执行。spring 版本为:5.0.x**)
```java
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {if (beanName.equals("userService")) {return null;}
        return pvs;
    }
}
```
当然,除了这个形式后,增加如下代码后也能使 `@Autowired` 注解的性能生效,```java
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {return false;}
}
```
上述的形式次要是利用了 `populateBean` 办法的上面一段代码:
```java
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return;}
        }
    }
}
```


仔细的小伙伴应该能发现,这两种形式的区别就在于实现的是不同的办法,然而实现的是同一个接口 **InstantiationAwareBeanPostProcessor**,所以,咱们这里也能得出一个论断:`InstantiationAwareBeanPostProcessor` 类型的后置处理器能够让 spring`@Autowired` 注解性能生效, 具体体现在 `postProcessPropertyValues` 和 `postProcessAfterInstantiation` 办法。

五、总结

  • 看到这里,咱们当前可别再说 @Autowired 注解是 byType 注入了。@Autowired 注解的原理就是 AutowiredAnnotationBeanPostProcessor 这个后置处理器在背地默默付出,找出符合条件的属性并应用反射进行注入
  • 除此之外,咱们还学会了如何应用 InstantiationAwareBeanPostProcessor 后置处理器来毁坏 @Autowired 的性能。
  • I am a slow walker, but I never walk backwards.

正文完
 0