前言
关于Spring IOC的依赖注入(DI机制),之前虽有过分析,但总感觉一直落了一块:对@Autowired注解元数据的解析部分。
本篇文章重在拾遗,并且从依赖注入整体的流程上进行把握。因为个人觉得依赖注入对于Spring框架来说太重要了,所以用多少笔墨,强调多少遍都不为过。so希望本篇文章能继续为大家服务,帮助到大家~
在继续这篇文章之前,强烈建议还赌自己是"小白"的同学先观看博文:
【小家Spring】Spring依赖注入(DI)核心接口AutowireCandidateResolver深度分析,解析@Lazy、@Qualifier注解的原理
关于Spring的依赖注入(DI)
注入:为某个对象的外部资源赋值,注入某个对象所需要的外部资源(包括对象、资源、常量数据等)。
注意对这里我所说的外部资源的理解,理解了就好,不用刻意的咬文嚼字~
依赖注入:Dependency Injection,简称DI,说白了就是利用反射机制为类的属性赋值的操作。
关于@Autowired这个注解,我们再熟悉不过了,经常跟@Resource来做对比,这篇文章我们不讨论两者有何异同,仅分析@Autowired的深层原理
AutowiredAnnotationBeanPostProcessor
准备
解析@Resource注解的不是这个类,而是CommonAnnotationBeanPostProcessor,但本文只会以AutowiredAnnotationBeanPostProcessor为例做深入分析~~~(解析@Autowired)
为了更好的说明问题,以下面这个具体实例进行讲解:
@Service public class A implements AInterface { @Async @Override public void funA() { System.out.println("线程名称:" + Thread.currentThread().getName()); } } @Service public class B implements BInterface { @Autowired private AInterface a; @Override public void funTemp() { System.out.println("线程名称:" + Thread.currentThread().getName()); } @Override public void funB() { System.out.println("线程名称:" + Thread.currentThread().getName()); } }
源码分析
对于此类,其实@Autowired
的javadoc上就有提到:它是靠AutowiredAnnotationBeanPostProcessor
去完成解析结果的
Please consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor} class (which, by default, checks for the presence of this annotation).
先看一下AutowiredAnnotationBeanPostProcessor它的继承图表:
由此继承图标我们能得出如下结论:
- 实现了InstantiationAwareBeanPostProcessor接口,所以可以介入到Bean的实例化前后
- 实现了BeanPostProcessor,所以介入到Bean的初始化前后
- 实现了MergedBeanDefinitionPostProcessor,说明它可以合并bean的定义信息
- 实现了BeanFactoryAware,实现了PriorityOrdered
解析注解元信息阶段
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware { // 该处理器支持解析的注解们~~~(这里长度设置为4) 默认支持的是3个(当然你可以自己添加自定义的依赖注入的注解 这点非常强大) private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4); // @Autowired(required = false)这个注解的属性值名称 // A 'required' dependency means that autowiring should fail when no beans are found. private String requiredParameterName = "required"; // 这个值一般请不要改变(若改成false,效果required = false的作用是相反的了) private boolean requiredParameterValue = true; private int order = Ordered.LOWEST_PRECEDENCE - 2; // 对@Lookup方法的支持 本文不讨论 private final Set<String> lookupMethodsChecked = Collections.newSetFromMap(new ConcurrentHashMap<>(256)); // 构造函数注入,本文也不讨论 private final Map<Class<?>, Constructor<?>[]> candidateConstructorsCache = new ConcurrentHashMap<>(256); // 方法注入、字段filed注入 本文的重中之重 // 此处InjectionMetadata这个类非常重要,到了此处@Autowired注解含义已经没有了,完全被准备成这个元数据了 所以方便我们自定义注解的支持~~~优秀 // InjectionMetadata持有targetClass、Collection<InjectedElement> injectedElements等两个重要属性 // 其中InjectedElement这个抽象类最重要的两个实现为:AutowiredFieldElement和AutowiredMethodElement private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256); // 这是它唯一构造函数 默认支持下面三种租借(当然@Inject需要额外导包) // 请注意:此处@Value注解也是被依赖注入解析的~~~~~~~~ // 当然如果你需要支持到你的自定义注解,你还可以调用下面的set方法添加。。。 public AutowiredAnnotationBeanPostProcessor() { this.autowiredAnnotationTypes.add(Autowired.class); this.autowiredAnnotationTypes.add(Value.class); try { this.autowiredAnnotationTypes.add((Class<? extends Annotation>)ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader())); logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring"); } catch (ClassNotFoundException ex) { // JSR-330 API not available - simply skip. } } // 下面两个方法可以自定义支持的依赖注入注解类型 public void setAutowiredAnnotationType(Class<? extends Annotation> autowiredAnnotationType) { Assert.notNull(autowiredAnnotationType, "'autowiredAnnotationType' must not be null"); this.autowiredAnnotationTypes.clear(); this.autowiredAnnotationTypes.add(autowiredAnnotationType); } public void setAutowiredAnnotationTypes(Set<Class<? extends Annotation>> autowiredAnnotationTypes) { Assert.notEmpty(autowiredAnnotationTypes, "'autowiredAnnotationTypes' must not be empty"); this.autowiredAnnotationTypes.clear(); this.autowiredAnnotationTypes.addAll(autowiredAnnotationTypes); } ... // 省略其余get/set方法 // bean工厂必须是ConfigurableListableBeanFactory的(此处放心使用,唯独只有SimpleJndiBeanFactory不是它的子类而已~) @Override public void setBeanFactory(BeanFactory beanFactory) { if (!(beanFactory instanceof ConfigurableListableBeanFactory)) { throw new IllegalArgumentException("AutowiredAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory: " + beanFactory); } this.beanFactory = (ConfigurableListableBeanFactory) beanFactory; } // 第一个非常重要的核心方法~~~ //它负责1、解析@Autowired等注解然后转换 // 2、把注解信息转换为InjectionMetadata然后缓存到上面的injectionMetadataCache里面 // postProcessMergedBeanDefinition的执行时机非常早,在doCreateBean()前部分完成bean定义信息的合并 @Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { // findAutowiringMetadata方法重要,完成了解析注解、缓存下来的操作 InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null); // 检查~~~(不太重要,可忽略) metadata.checkConfigMembers(beanDefinition); } // 方法名为查找到该bean的依赖注入元信息,内部只要查找到了就会加入到缓存内,下次没必要再重复查找了~ // 它是一个模版方法,真正做事的方法是:buildAutowiringMetadata 它复杂把标注有@Autowired注解的属性转换为Metadata元数据信息 从而消除注解的定义 // 此处查找包括了字段依赖注入和方法依赖注入~~~ private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) { String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) { synchronized (this.injectionMetadataCache) { metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) { if (metadata != null) { metadata.clear(pvs); } metadata = buildAutowiringMetadata(clazz); this.injectionMetadataCache.put(cacheKey, metadata); } } } return metadata; } // 这里我认为是整个依赖注入前期工作的精髓所在,简单粗暴的可以理解为:它把以依赖注入都转换为InjectionMetadata元信息,待后续使用 // 这里会处理字段注入、方法注入~~~ // 注意:Autowired使用在static字段/方法上、0个入参的方法上(不会报错 只是无效) // 显然方法的访问级别、是否final都是可以正常被注入进来的~~~ private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) { List<InjectionMetadata.InjectedElement> elements = new ArrayList<>(); Class<?> targetClass = clazz; // 小细节:这里是个do while循环,所以即使在父类,父父类上依赖注入依旧是好使的(直到Object后停止) do { final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>(); ReflectionUtils.doWithLocalFields(targetClass, field -> { AnnotationAttributes ann = findAutowiredAnnotation(field); if (ann != null) { // static属性不好使 if (Modifier.isStatic(field.getModifiers())) { if (logger.isInfoEnabled()) { logger.info("Autowired annotation is not supported on static fields: " + field); } return; } //解析required属性(若存在) 最终封装成AutowiredFieldElement boolean required = determineRequiredStatus(ann); currElements.add(new AutowiredFieldElement(field, required)); } }); ReflectionUtils.doWithLocalMethods(targetClass, method -> { Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) { return; } AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod); if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { // static方法不好使 if (Modifier.isStatic(method.getModifiers())) { if (logger.isInfoEnabled()) { logger.info("Autowired annotation is not supported on static methods: " + method); } return; } // 方法没有入参不好使 if (method.getParameterCount() == 0) { if (logger.isInfoEnabled()) { logger.info("Autowired annotation should only be used on methods with parameters: " + method); } } boolean required = determineRequiredStatus(ann); PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); // AutowiredMethodElement里封装了一个PropertyDescriptor(比字段多了一个参数) currElements.add(new AutowiredMethodElement(method, required, pd)); } }); // 小细节:父类的都放在第一位,所以父类是最先完成依赖注入的 elements.addAll(0, currElements); targetClass = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class); // 可见InjectionMetadata就是对clazz和elements的一个包装而已 return new InjectionMetadata(clazz, elements); } // 只要方法/属性上但凡标注有一个注解,就立马返回了~~(so你标注多个最终生效的只会有一个哦) @Nullable private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) { if (ao.getAnnotations().length > 0) { // autowiring annotations have to be local for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) { AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type); if (attributes != null) { return attributes; } } } return null; } // 小细节这个方法是protected的 protected boolean determineRequiredStatus(AnnotationAttributes ann) { return (!ann.containsKey(this.requiredParameterName) || this.requiredParameterValue == ann.getBoolean(this.requiredParameterName)); } ... // 关于内部类inject的最终可以放在下面的重点 }
这一步,借助postProcessMergedBeanDefinition()方法完成了对该bean中所有的依赖注入的属性、方法完成了原始元信息的转换,已经把依赖注入的相关注解全都转换成了InjectionMetadata,这样后面的使用过程中将不再需要再和具体注解打交道,而是做着一些和业务无关的动作即可。
注入阶段
这是核心阶段,也是最为复杂的阶段,当然前面的解析已经为本步骤做好了元数据的铺垫。
我们知道在Bean的创建过程中,完成Bean的实例化后,会调用方法AbstractAutowireCapableBeanFactory#populateBean()完成对Bean的属性赋值,从而就会触发InstantiationAwareBeanPostProcessor.postProcessPropertyValues()方法给属性进行赋值,这处也就是本步骤的入口~
注意:Spring5.1之后把此方法@Deprecated了,用postProcessProperties方法代替(这个方法名语义更清晰,单纯的方法名的改动而已,内容无任何变动~~)
// @since 2.5 public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware { ... @Deprecated // 标注为过期,直接调用postProcessProperties方法 @Override public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) { return postProcessProperties(pvs, bean, beanName); } @Override public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { // 从缓存中取出这个bean对应的依赖注入的元信息~ InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); //(生路异常处理部分代码)所以事情都委托给了InjectionMetadata 的inject方法 // 此处注意InjectionMetadata是会包含多个那啥的~~~(当然可能啥都没有 没有依赖注入的东东) //InjectionMetadata.inject内部查看也十分简单:最终都还是委托给了InjectedElement.inject实例去处理的 metadata.inject(bean, beanName, pvs); return pvs; } }
综上能够发现,最终依赖注入实际做事的是InjectedElement,这个抽象类有好几个实现,此处我们以使用最为广泛的AutowiredFieldElement进行说明