源码深入解析spring 的初始化方法 initMethod (标有注解的@postConstruct的方法)--极度细致!

一.说在前面(结论思考)

@postConstruct 所标注的方法 内部是靠的spring提供的两个后置处理器(InitDestroyAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor)共同 协调分布处理完成的。 这2点也是网上绝大部人没讲明白的,很多人都只是说到一个,其实我之前看源码也是以为一个,结果,后面由于xxx 我发现了是两个!!还有就是他们各种如何协调作用完成工作的?是各自又是在 bean 的生命周期的哪一个阶段`起的作用?

二.弄清InitDestroyAnnotationBeanPostProcessor CommonAnnotationBeanPostProcessor的关系

这两个后置处理器还是父子关系:InitDestroyAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor
源码深入解析spring 的初始化方法 initMethod (标有注解的@postConstruct的方法)--极度细致!
说明:MergedBeanDefinitionPostProcessor 这个后置处理器接口中
1、postProcessMergedBeanDefinition
缓存bean的注入信息的后置处理器,仅仅是缓存或者干脆叫做查找更加合适,没有完成注入,注入是另外一个后置处理器的作用

1.CommonAnnotationBeanPostProcessor

a.提供的方法 postProcessMergedBeanDefinition 可以看作处理解析注解入口–> 其时它处理 @Resouce 的字段注入
–> 所以可以看到它自身 维护了一个 缓存injectionMetadataCache <String, InjectionMetadata> 这个 map 的value是包含了 每一个bean类所依赖属性 字段(可能多个) 是被 标注由 @Resouce 的 封装为 InjectionMetadata对象,key为beanName
–> 他里面有个方法是 autowireResouce(Beanfactory,LookupElenment,string) 完成对 依赖字段的处理
具体的 postProcessMergedBeanDefinition 被调用及作用见下图很重要!:
源码深入解析spring 的初始化方法 initMethod (标有注解的@postConstruct的方法)--极度细致!

2.InitDestroyAnnotationBeanPostProcessor

其实只是解析了 bean上面有标注 @PostConstruct、@ PreDestroy 的方法们,
–> 所以我们同可以在它里面维护了1个缓存lifecycleMetadaCache<Class, LifecycleMetada> ,这个 map就是在解析的过程中完成 --> value是包含了 每一个bean类(只能1个,还不能静态源码看到!) 是被 标注由 @PostConstruct、@ PreDestroy的 先各自对应封装的方法集合,后两个集合方法共同封装为 InjectionMetadata对象,key为beanClass

– 刚上面提到的–>解析具体是在何时哪个阶段完成的呢?
–> 其实是在上面的子类 CommonAnnotationBeanPostProcessor 的 postProcessMergedBeanDefinition被调用时候执行!

3.总结关系

  1. 注解解析为缓存: @PostConstruct、@ PreDestroy 及 @Rerosuce 的解析是发生在–》bean生命周期的实例化后,pupulate 设置属性前, 通过 【apply_Merged_BeanDefinitionPostProcessors】利用 合并后置处理器接口方法调用到 CommonAnnotationBeanPostProcessor 他的postProcessMergedBeanDefinition逻辑完成注解(方法,字段)解析放到了其和父类的两个缓存map里面,具体使用在下面
  2. 注解方法调用:(我们暂时不关注注解字段 即 @Rerosuce解析的缓存使用)
    注解方法如–》 @PostConstruct 注解的方法被调用反射处理 A 中方法是在 整个init 初始化阶段的before阶段即:【apply_BeanPostProcessors_BeforeInitialization】获取到所有的处理器们,其中执行到 InitDestroyAnnotationBeanPostProcessor. 方法postProcessBeforeInitialization(注意其实都是获取处理器是 CommonAnnotationBeanPostProcessor,InitDestroyAnnotationBeanPostProcessor 都没有bd的 见下面注意说明!),这里面会发生“先取后用”` 的操作,见下图:

源码深入解析spring 的初始化方法 initMethod (标有注解的@postConstruct的方法)--极度细致!

3.注意:

其实2.中所说的获取到处理器执行到 InitDestroyAnnotationBeanPostProcessor 不是直接到的!!,这里有一个小点!!即我们经常看到的获取所有的处理器们 getBeanPostProcessors()这个方法其实返回的是 bean工厂里面单独所维护 的一个后置处理器的一个集合 List<BeanPostProcessor> beanPostProcessors,而其实InitDestroyAnnotationBeanPostProcessor 这个后置处理器是没有在这个集合中的!!但是他的所继承的子类CommonAnnotationBeanPostProcessor是在的 ,即我们刚说的调用都是掉的父类处理器
CommonAnnotationBeanPostProcessor只不过 这个后置处理器根本没有重写 父类处理器InitDestroyAnnotationBeanPostProcessor的方法 postProcessBeforeInitialization,所以调用链是直接进入 到InitDestroyAnnotationBeanPostProcessor里面的!,其实这样是对的,否则就执行两次了!
其实看bdMap(图)也知 InitDestroyAnnotationBeanPostProcessor 居然根本就是没有生成bd的,之前我一直以为这个处理器也是在spring容器中的,害我想复杂了很多,哎!,也是,它的功能都是被子类所继承下来的且子类 CommonAnnotationBeanPostProcessor 是在spring容器里,即后面的操作它作为父类的功能都是能被子类所用到,所以spirng没有必要将他放入容器,还免得出现执行混乱!–》 我觉得这个也算是理解spirng的一个点!精简准确性!
源码深入解析spring 的初始化方法 initMethod (标有注解的@postConstruct的方法)--极度细致!

插一句(可能插的有点长哈):
(这里其实可以解释到为啥jdk版本不同,到这@postConstuct 和 @Resouce 可能不生效!的原因,–> 因为 CommonAnnotationBeanPostProcessor 这个后置处理器是来处理了 a. @PostConstruct、@ PreDestroy + [email protected] 两大类注解的实现, 为啥说是两个大类呢? 因为,a. 类注解是用在方法上面表示init相关, 而 b.类 @Resouce 是处理字段上面自动注入的类似 @Autowired,(从类图方法也可以看到) 在这里就显得有点另类了,我当时也非常奇怪为啥它明明是来处理对象的依赖字段属性注入相关的,为啥它要放到这个后置处理器中处理,而非是像@Autowired 是由 AutowireAnnotationBeanPostProcessor 来处理的,–> 后面我的理解是: @Resouce 和初始化的注解 都不是spring框架自带的,而 @Autowired 却是,这也就是说, @Resouce 等注解因为它不属于spring的一部分即它可能是因为jdk的版本不同是加载不到类的,如jdk9,11由于xx就是加载不上的!,而我们的 @Autowired 是非常极度常用且是spring自己所带的所以一定能保证它的解析加载依赖属性正常,即 AutowireAnnotationBeanPostProcessor 是可以被放入到spirng容器里,重点来了!如果我们讲有可能出问题的 @Resouce 等注解的解析功能也放到 AutowireAnnotationBeanPostProcessor里面话,那么就可能会导致 这个非常重要的基础处理器都无法放入spring中即spring就基本失效了!,所以 spring 给分开了保证即使由于外部原因 CommonAnnotationBeanPostProcessor 无法正常加入spring,也能基本实现大部分功能! )

未完待续----