- Published on
Spring容器的重要组件(invokeBeanFactoryPostProcessor 方法)
怎么理解容器
容器是一个抽象的概念,是由一些列组件组合在一起完成spring bean
管理的工作;容器主要有两种分别BeanFactory
和ApplicationContext
;BeanFactory
是一个简单的容器,能完成bean
的实例化,bean
的依赖注入;早期开发应用程序资源有限,试 用BeanFactory
可以节省很大的资源;说个最简单的比方BeanFactory
当中的bean
都是懒加载的,但 是随着互联网的发展现在的资源已经没有那么紧张了(比如内存),绝大部分情况下都是用
ApplicationContext
这个容器他们主要区别在于ApplicationContext
的功能比较丰富,支持国际化、支持事件发布、支持
以ApplicationContext
为例他有一个经典的实现AnnotationConfigApplicationContext
改容器当中有一个非常重要的组件**DefaultListableBeanFactory
对象;这个对象当中有一个组件 beanDefinitionMap
主要来存储所有扫描出来的beandefinition
**;这个容器里面的组件非常多。
执行顺序、时机
1、关于beanDefinitionMap
当中的内置的值 当spring容器执行到invokeBeanFactoryPostProcessors
方法的时候,并没有完成扫描、但是 beanDefinitionMap
当中有6个值(你提供了配置类),其中前五个是spring内置的;
实在执行AnnotationConfigApplicationContext
的构造方法当中执行new AnnotatedBeanDefinitionReader(this);
的时候就put到里面了;第六个是我们配置类我们手动添加的, spring调用了register方法put到里面的
2、invokeBeanFactoryPostProcessors
方法是执行所有的可靠的BeanFactoryPostProcessor
BeanFactoryPostProcessor
有一个子类BeanDefinitionRegistryPostProcessor
;
父类当中的方法是postProcessBeanFactory
,子类的方法是postProcessBeanDefinitionRegistry
根据实现的接口和来源不同我们讲类分为以下几类
下面是代码示例,参考Spring源码 example 工程:
注意:ccpp
==ConfigurationClassPostProcessor
spring
执行顺序总体上是先执行子类在执行父类;- 先执行api提供的;
- 然后执行内置的实现了
PriorityOrdered
接口的; - 继而执行扫描出来的或者动态bd添加的实现了
Orderd
接口的,需要说明的是PriorityOrdered
是继承了Orderd
的。
故而最后实现什么都实现的所以顺序是:
C#postProcessBeanDefinitionRegistry
因为api提供最先ccpp#postProcessBeanDefinitionRegistry
内置且实现了PriorityOrdered
I#postProcessBeanDefinitionRegistry
扫描出来的实现了PriorityOrdered
(Orderd
)D#postProcessBeanDefinitionRegistry
被扫描出来的,没有实现,他添加了F
F#postProcessBeanDefinitionRegistry
动态添加的子类
--------------------------------所有子类执行完了-------------------------------
C#postProcessBeanFactory
C是api且实现了子类提供级别真的高(注意对比B)ccpp#postProcessBeanFactory
内置的I#postProcessBeanFactory
实现了PriorityOrdered
d#postProcessBeanFactory
作为子类动态添加的 比F先是因为字母排序f#postProcessBeanFactory
作为子类动态添加的b#postProcessBeanFactory
api调用的,但是B没有实现子类,所以级别较低h#postProcessBeanFactory
直接实现父类,比B低(b是api提供)H是扫描a#postProcessBeanFactory
为什么A 比H低,A也是直接实现父类-H实现了排序接口
问题思考(重点)
只要把上面的顺序搞懂了这些问题才会变得有意义
1、这样的顺序能不能变
最好不要变;子类高于父类无可厚非,实现了排序的先执行也无可厚非;唯一有争议的是为什么api的先调用;
spring是想尽量充分利用了postProcessBeanDefinitionRegistry
方法的意义;避免注入不完整 的bean;因为如果一个bean在扫描之后之后添加可能会有些功能不完善,api放到最前就不会有这个问题。
2、通过api提供的bean存到了list当中,不会重复执行
3、如何确保postProcessBeanDefinitionRegistry方法对子类类型的bd的修改最大化生效
同级别子类修改一个子类的bd会失效(对普通类的修改不会失效),因为spring是找出同级别的bean
直接实例化存到集合当中,然后一起执行,这样在执行第一个的时候如果修改了第二个的bd则无效(这也不是bug,估计作者不想搞的太复杂)
但是对普通类的修改就不会失效了,因为普通类实例化特别靠后,你修改一定会生效;如果你一定需要修改一个子类的bd,最好提高当前子类的级别
4、BeanDefinitionRegistryPostProcessor和ImportBeanDefinitionRegistart的区别
ImportBeanDefinitionRegistart
回调的时候可以获取注解信息ImportBeanDefinitionRegistart
的执行时机早于BeanDefinitionRegistryPostProcessor
(除api 提供)BeanDefinitionRegistryPostProcessor
(除api提供)对一些bean的注册可能有些功能会失效比 如@BeanImportBeanDefinitionRegistart
没有上述问题,因为他是在ccpp
内部执行的- 如果你一定要动态注册bd,尽量推荐试用
ImportBeanDefinitionRegistart
- 除非你除了要动态添加bd还需要对
beanFactory
做一些全局设定,那么可以用BeanDefinitionRegistryPostProcessor
因为他是一个bean工厂后置处理器
5、我们不推荐用BeanFactoryPostProcessor来注册beandefinition
BeanFactoryPostProcessor
的优先级比BeanDefinitionRegistryPostProcessor
还要低
6、mybatis的扩展新版和老版的区别
老版简单粗暴容易理解,新版有画蛇添足之嫌;为什么新版搞这么复杂呢?可以先自己思考一下
关于BeanFactoryPostProcessor
怎么理解bean工厂的后置处理器?
主要是提供给程序员扩展的;在spring容器初始化期间可以让程序员对BeanFactory组件进行全局设置,比如修改、添加beandefinition、比如设置忽略类型、比如设置忽略接口;这节课我们先分析两个
主要的api,后面会做更多api的分析
1、void ignoreDependencyType(Class<?> type);
在自动注入的模型下忽略type类型bean的注入,对所有bean都生效
2、void ignoreDependencyInterface(Class<?> ifc);
一般情况下ifc
是个接口,一般情况下ifc
里面有一个setter;如果某个bean实现了 ifc
接口,那么必然会 重写里面的setter
,而重写的这个setter
就不会被自动注入;
主要作用也是忽略某个类型的bean的自动注 入;但是ignoreDependencyInterface
不能对所有bean生效,你得实现ifc
接口才能对忽略的设置生效。