一.说在前面(结论思考)
@postConstruct 所标注的方法 内部是靠的spring提供的两个后置
处理器(InitDestroyAnnotationBeanPostProcessor
和 CommonAnnotationBeanPostProcessor
)共同 协调分布处理完成的。 这2点也是网上绝大部人没讲明白的,很多人都只是说到一个,其实我之前看源码也是以为一个,结果,后面由于xxx 我发现了是两个!!还有就是他们各种
如何协调作用完成工作的?是各自又是
在 bean 的生命周期的哪一个阶段`起的作用?
二.弄清InitDestroyAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
的关系
这两个后置处理器还是父子关系:InitDestroyAnnotationBeanPostProcessor
和 CommonAnnotationBeanPostProcessor
说明:MergedBeanDefinitionPostProcessor
这个后置处理器接口中
1、postProcessMergedBeanDefinition
缓存bean的注入信息的后置处理器,仅仅是缓存或者干脆叫做查找更加合适
,没有完成注入,注入是另外一个后置处理器的作用
1.CommonAnnotationBeanPostProcessor
a.提供的方法 postProcessMergedBeanDefinition 可以看作处理解析 注解 到缓存的入口
–> 其时它处理 @Resouce
的字段,解析bean中包含此注解的字段封装对象到缓存 ,以供 requeBean 在 pupulateBean 阶段 取出来用到完成 依赖注入
。
(和我们这篇讨论的有区别!!,但引出个问题,那对应的注解@Autowired
用在字段或方法时候,又是在哪个处理器 解析到缓存?它应该类似 @resouce 都有个解析到缓存,先缓存再使用 的过程!)
–> 所以可以看到它自身 维护了一个 缓存
:injectionMetadataCache
<String,InjectionMetadata>
这个 map 的value是包含了 每一个bean类所依赖属性 字段(可能多个) 是被 标注由 @Resouce 的 封装为 InjectionMetadata对象,key为beanName
–> 他里面有个方法是 autowireResouce(Beanfactory,LookupElenment,string) 完成对 依赖字段的处理
具体的 postProcessMergedBeanDefinition 被调用及作用见下图很重要!:
2.InitDestroyAnnotationBeanPostProcessor
其实只是解析了 bean上面有标注 @PostConstruct、@ PreDestroy 的方法们,
–> 所以我们同可以在它里面维护了1个缓存
:lifecycleMetadaCache
<Class, LifecycleMetada> ,这个 map就是在解析的过程中完成 --> value是包含了 每一个bean类(只能1个,还不能静态源码看到!) 是被 标注由 @PostConstruct、@ PreDestroy的 先各自对应封装的方法集合,后两个集合方法共同封装为 InjectionMetadata对象
,key为beanClass
– 刚上面提到的–>解析具体是在何时哪个阶段完成的呢?
–> 其实是在上面的子类 CommonAnnotationBeanPostProcessor 的 postProcessMergedBeanDefinition被调用时候执行!
3.总结关系
- 注解解析为缓存: @PostConstruct、@ PreDestroy 及 @Rerosuce 的解析是发生在–》bean生命周期的实例化后,pupulate 设置属性前, 通过 【apply_Merged_BeanDefinitionPostProcessors】利用 合并后置处理器接口方法调用到
CommonAnnotationBeanPostProcessor
他的postProcessMergedBeanDefinition
逻辑完成注解(方法,字段)解析
放到了其和父类的两个缓存
map里面,具体使用在下面 - 注解方法调用:
(我们暂时不关注注解字段 即@Rerosuce解析的缓存使用
–> 因为他的使用是属于依赖注入相关,是在pupulateBean
阶段
参考另外一篇单独讲依赖注入:https://blog.csdn.net/qq_39965727/article/details/104672027)
注解方法如–》 @PostConstruct 注解的方法被调用反射处理 A 中方法是在 整个init 初始化阶段的before阶段即:【apply_BeanPostProcessors_BeforeInitialization】获取到所有的处理器们,其中执行到 InitDestroyAnnotationBeanPostProcessor
. 方法postProcessBeforeInitialization
(注意其实都是获取处理器是 CommonAnnotationBeanPostProcessor,InitDestroyAnnotationBeanPostProcessor 都没有bd
的 见下面注意说明!),这里面会发生
“先取后用”` 的操作,见下图:
3.注意:
其实2.中所说的获取到处理器执行到 InitDestroyAnnotationBeanPostProcessor 不是直接到的!!,这里有一个小点!!即我们经常看到的获取所有的处理器们 getBeanPostProcessors()这个方法其实返回的是 bean工厂里面单独所维护 的一个后置处理器的一个集合 List<BeanPostProcessor> beanPostProcessors,
而其实InitDestroyAnnotationBeanPostProcessor 这个后置处理器是没有在这个集合中的!
!但是他的所继承的子类CommonAnnotationBeanPostProcessor是在的 ,即我们刚说的调用都是掉的父类处理器
CommonAnnotationBeanPostProcessor只不过 这个后置处理器根本没有重写 父类处理器InitDestroyAnnotationBeanPostProcessor的方法 postProcessBeforeInitialization
,所以调用链是直接进入 到InitDestroyAnnotationBeanPostProcessor里面的!,其实这样是对的,否则就执行两次了!
其实看bdMap(图)也知 InitDestroyAnnotationBeanPostProcessor 居然根本就是没有生成bd的,
之前我一直以为这个处理器也是在spring容器中的,害我想复杂了很多,哎!,也是,它的功能都是被子类所继承下来的且子类 CommonAnnotationBeanPostProcessor 是在spring容器里,即后面的操作它作为父类的功能都是能被子类所用到,所以spirng没有必要将他放入容器,还免得出现执行混乱!–》 我觉得这个也算是理解spirng的一个点
!精简准确性!
插一句(可能插的有点长哈):
(这里其实可以解释到为啥jdk版本不同,到这@postConstuct 和 @Resouce 可能不生效!的原因,–> 因为 CommonAnnotationBeanPostProcessor 这个后置处理器是来处理了 a. @PostConstruct、@ PreDestroy
+ b.@Resource
两大类注解的实现, 为啥说是两个大类呢? 因为,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,也能基本实现大部分功能! )
未完待续----