前言
- 基于上篇文章从源码的角度查找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()
办法
- 第一:获取到bean对应的
- 或者间接在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
办法,持续调试代码,如下图所示:
此时咱们跟着断点走,进入到AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues办法,如下图所示:
咱们继续执行,将断点打到办法的出口处,如下图所示:
综上所述,@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.
发表回复