前言
- 本文将总结下Spring依赖注入动态属性失败以及增加set办法就能解决的原理
一、测试项目
AppConfig.java
@Configuration@ComponentScan("com.eugene.sumarry.csdn.autowiredstatic")public class AppConfig {}
UserDao.java
@Repositorypublic class UserDao {}
UserService.java
@Servicepublic class UserService { @Autowired private UserDao userDao; @Override public String toString() { return "UserService{" + "userDao=" + userDao + '}'; }}
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中依赖注入UserDao动态变量及运行后果(
动态变量注入失败
):
- UserService.java中依赖注入UserDao实例实例变量及运行后果(实例变量注入胜利):
- 增加set办法实现动态变量的依赖注入(
动态变量注入胜利
):
留神: 应用构造方法也能够实现注入,然而应用构造方法来注入并不是@Autowired注解实现的性能,因为你会发现,你加与不加@Autowired注解都会实现注入。此时是通过构造方法进行依赖注入的(如果读者不信,读完上面的 【原理】章节后能够本人debug调试)。本文解说的是@Autowired注解的原理,所以不思考构造方法的依赖注入
三、原理
背景常识: Spring的依赖注入形式有很多种,对Spring而言常见的有如下四种
常见依赖注入类型 备注 AbstractBeanDefinition.AUTOWIRE_NO 不开启主动拆卸性能 AbstractBeanDefinition.AUTOWIRE_BY_NAME 依据变量名来主动拆卸 AbstractBeanDefinition.AUTOWIRE_BY_TYPE 依据类型主动拆卸 AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR 依据构造方法主动拆卸 而针对于@Autowired注解的依赖注入,最终都会通过
AutowiredAnnotationBeanPostProcessor
后置处理器来解决,针对于此篇博客而言,是它的MergedBeanDefinitionPostProcessor身份起的作用
对于尔后置处理器的作用能够查看我之前公布的博客:spring 5.0.x源码学习系列八: 实例化bean之应用构造方法创立bean、主动拆卸与循环依赖的第三章: spring bean实例化过程中波及到的后置处理器和执行程序。最终,通过AutowiredAnnotationBeanPostProcessor
后置处理器的解决,会将以后类的所有反对主动拆卸属性以InjectionMetadata
类型的对象保留,那到底是反对哪些属性的主动拆卸的呢?持续往下看。。
3.1 spring如何抉择@Autowired注解标识的变量进行依赖注入
- 请先看下图中的正文及源码解释
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata源码剖析
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) { // 寄存以后类包含父类中带@Autowired注解的字段和办法 List<InjectionMetadata.InjectedElement> elements = new ArrayList<>(); Class<?> targetClass = clazz; do { // 寄存targetClass中所有带了@Autowired注解的字段和办法 final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>(); ReflectionUtils.doWithLocalFields(targetClass, field -> { // JDK1.8 新个性,传入一个办法进去,在办法外部就是获取以后类的所有字段(不包含父类, // 包含本人定义的公有变量),并循环调用传入的办法, // 即以后办法 // 判断以后字段是否有@Autowired注解 AnnotationAttributes ann = findAutowiredAnnotation(field); if (ann != null) { // 判断以后字段是否为static润饰 ===> 动态变量, 如果是,则只是返回了 if (Modifier.isStatic(field.getModifiers())) { if (logger.isWarnEnabled()) { logger.warn("Autowired annotation is not supported on static fields: " + field); } return; } boolean required = determineRequiredStatus(ann); // 将字段包装成AutowiredFieldElement对象,并存入一开始创立的list中 currElements.add(new AutowiredFieldElement(field, required)); } }); ReflectionUtils.doWithLocalMethods(targetClass, method -> { // 同上,此时获取的是以后class外部的method(不包含父类, 包含本人定义的公有办法 // ),并挨个遍历执行以后传入的办法 // 判断遍历的办法是否为桥接办法 Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) { return; } // 拿到以后办法的@Autowired注解,并进行校验拿到实在办法(因为有可能以后要解决的类是一个代理对象,或者接口等等) AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod); if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { // 判断以后办法是否为静态方法 if (Modifier.isStatic(method.getModifiers())) { if (logger.isWarnEnabled()) { logger.warn("Autowired annotation is not supported on static methods: " + method); } return; } if (method.getParameterCount() == 0) { if (logger.isWarnEnabled()) { logger.warn("Autowired annotation should only be used on methods with parameters: " + method); } } boolean required = determineRequiredStatus(ann); // 找到以后办法中的参数形容器 PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); // 将set办法和要传入的属性的形容器包装成AutowiredMethodElement类并增加至一开始创立的list汇合中 currElements.add(new AutowiredMethodElement(method, required, pd)); } }); elements.addAll(0, currElements); // 获取父类的class,针对父类的属性和办法在做筛选 targetClass = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class); // 最终返回一个InjectionMetadata对象,其中蕴含以后类及其父类(不蕴含Object类)的所有带 // @Autowired注解的办法和子弹 return new InjectionMetadata(clazz, elements);}
- 综上,AutowiredAnnotationBeanPostProcessor后置处理器的MergedBeanDefinitionPostProcessors后置处理器的作用就是将以后类及其父类(不蕴含Object类)的所有蕴含@Autowired注解的非动态字段和非动态带参办法以InjectionMetadata对象的形式保留在
injectionMetadataCache
属性中
3.2 spring在进行依赖注入时的逻辑
- 在进行依赖注入时,必定是执行了
populateBean
办法,具体后果如下图所示:
至此,spring针对依赖注入的性能的筹备工作
算是实现了。为什么说是筹备工作呢?因为后续还要执行真正的inject
注入属性办法,最初会通过Spring的beanFacotry或者间接从cache中拿依赖对象,最初进行属性赋值。至此,Spring @Autowired注解的解决流程就完结了。
四、总结
- 综上所述,针对@Autowired注解的解决流程次要外围为AutowiredAnnotationBeanPostProcessor后置处理器的MergedBeanDefinitionPostProcessor身份,它会去筛选出所有带@Autowired注解的非动态字段和非静态方法作为候选者,最终再通过spring的bean工厂去获取依赖的对象,应用反射的技术实现注入
- I am a slow walker, but I never walk backwards.