虽然我们前面的文章提到,第三方框架mybatis对于spring的集成使用的是
FactoryBean+ImportBeanDefifinitionRegistrar+@Import对mapper进行注入的方案。
但对于动态注册/修改BeanDefinition的方式仍然存在两种方式:
1)、BeanFactoryPostProcess
可以修改BeanDefinition、注册不完整的BeanDefinition(这里后面会提到为什么是不完整的)
2)、BeanDefinitionRegistryPostProcessor
可以注册修改BeanDefinition。(功能和ImportBeanDefifinitionRegistrar类似)(BeanFactoryPostProcess的子接口)
而spring中对于我们自己注入的对象,在invokeBeanFactoryPostProcessors方法中会去处理这两种动态注入BeanDefinition的方式(当然这个方法不止这个功能)。我们要解决之前几篇文章遗留下来的问题,需要先看看invokeBeanFactoryPostProcessors方法是如何运行的。
1、探究两个接口实现方法的执行顺序
我们从几个因素出发,探究父接口BeanFactoryPostProcess和子接口BeanDefinitionRegistryPostProcessor对应的方法的执行时机:
1)、对象注入方式:调用容器api、使用注解、动态注册BeanDefinition
2)、是否实现PriorityOrdered接口
为此我们准备了几个类用来测试
A类:
@Component
public class A implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// BeanDefinitionBuilder k = BeanDefinitionBuilder.genericBeanDefinition(K.class);
//
// DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
// defaultListableBeanFactory.registerBeanDefinition("k",k.getBeanDefinition());
/*BeanDefinitionBuilder x = BeanDefinitionBuilder.genericBeanDefinition(X.class);
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
defaultListableBeanFactory.registerBeanDefinition("x",x.getBeanDefinition());*/
System.out.println("A --impl BeanFactoryPostProcessor--- by @Component ---- Override postProcessBeanFactory");
}
}
B类:
public class B implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("B--impl BeanFactoryPostProcessor---By api----Override postProcessBeanFactory");
}
}
C类:
public class C implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("C--impl BeanDefinitionRegistryPostProcessor---by api ----Override postProcessBeanFactory");
//log.debug("c-s api parent postProcessBeanFactory");
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("C --impl BeanDefinitionRegistryPostProcessor---by api ----Override postProcessBeanDefinitionRegistry");
//log.debug("c-s api subclass postProcessBeanDefinitionRegistry");
// BeanDefinitionBuilder x= BeanDefinitionBuilder.genericBeanDefinition(X.class);
// registry.registerBeanDefinition("x",x.getBeanDefinition());
}
}
D类:
@Component
public class D implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("D -- impl BeanDefinitionRegistryPostProcessor--- by @Component ---- Override postProcessBeanFactory");
//log.debug("d-s scan parent postProcessBeanFactory");
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("D -- impl BeanDefinitionRegistryPostProcessor--- by @Component ---- Override postProcessBeanDefinitionRegistry");
//log.debug("d-s scan subclass postProcessBeanDefinitionRegistry register E F");
BeanDefinitionBuilder e = BeanDefinitionBuilder.genericBeanDefinition(E.class);
BeanDefinitionBuilder f= BeanDefinitionBuilder.genericBeanDefinition(F.class);
// AbstractBeanDefinition j = (AbstractBeanDefinition) registry.getBeanDefinition("j");
// j.setBeanClass(L.class);
registry.registerBeanDefinition("e",e.getBeanDefinition());
registry.registerBeanDefinition("f",f.getBeanDefinition());
}
}
E类:
public class E implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("E -- impl BeanFactoryPostProcessor--- by BeanDefinition ---- Override postProcessBeanFactory");
//log.debug("e-p bd parent postProcessBeanFactory");
}
}
F类:
public class F implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("F-- impl BeanDefinitionRegistryPostProcessor---by BeanDefinition ---- Override postProcessBeanFactory");
//log.debug("f-s bd parent postProcessBeanFactory");
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("F -- impl BeanDefinitionRegistryPostProcessor--- by BeanDefinition----Override postProcessBeanDefinitionRegistry");
//log.debug("f-s bd subclass postProcessBeanDefinitionRegistry");
}
}
H类:
@Component
public class H implements BeanFactoryPostProcessor, PriorityOrdered {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("H -- impl BeanFactoryPostProcessor + PriorityOrdered--- by @Component----Override postProcessBeanFactory");
//log.debug("h-p scan parent postProcessBeanFactory PriorityOrdered");
}
@Override
public int getOrder() {
return 0;
}
}
I类:
@Component
public class I implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("I --impl BeanDefinitionRegistryPostProcessor + PriorityOrdered--- by @Component ---- Override postProcessBeanFactory");
//log.debug("i-s scan parent postProcessBeanFactory PriorityOrdered");
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("I -- impl BeanDefinitionRegistryPostProcessor + PriorityOrdered---by @Component ----Override postProcessBeanDefinitionRegistry");
//log.debug("i-s scan subclass postProcessBeanDefinitionRegistry PriorityOrdered");
// AbstractBeanDefinition j = (AbstractBeanDefinition) registry.getBeanDefinition("j");
// j.setBeanClass(L.class);
// BeanDefinitionBuilder x= BeanDefinitionBuilder.genericBeanDefinition(X.class);
// registry.registerBeanDefinition("x",x.getBeanDefinition());
}
@Override
public int getOrder() {
return 0;
}
}
ApplicationContextTest类
注意:B、C是通过Api方式注入的,是加入一个BeanFactoryPostProcessor,而非注册BeanDefinition,所以这两个类不会转为BeanDefinition put到BeanDefinitionMap,也不会实例化为Bean放进单例池,但是这两个类会去执行其父子实现类
public class ApplicationContextTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//api方式注入B
context.addBeanFactoryPostProcessor(new B());
context.addBeanFactoryPostProcessor(new C());
//手动api注入时,需要自己调用AnnotationConfigApplicationContext的无参构造,并register方法传入配置类
context.register(ContextConfig.class);
context.refresh();
}
}
ContextConfig类
@Component
@ComponentScan("com.spring.demo.invokeBeanFactoryPostProcessors")
public class ContextConfig {
}
启动,先直接看结果:
从结果可以推断出:
1)、子接口实现方法>>父接口方法
2)、api方式>>实现了PriorityOrdered接口>>通过注解注入>>动态注册BeanDefinition
3)、实现子接口比实现父接口更快执行
注意:其中还有spring内置类的执行,只是这里没有去打印出来。
此时我们直接进来源码
调用链:
refresh()-----》invokeBeanFactoryPostProcessors-------》
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors
源码:
/**
* 功能:执行实现了BeanFactoryPostProcessor/其子接口BeanDefinitionRegistryPostProcessor的方法
*
* */
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
/**
* 用来存放已经处理完的BeanFactoryPostProcessor以及其子类BeanDefinitionRegistryPostProcessor
* 防止重复执行
* 前提:这些类不是使用api进行注册的 留个疑问,为什么呢????(因为这些类不会出现重复执行的情况)
* */
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
//beanFactory---DefaultListableBeanFactory实现BeanDefinitionRegistry,所以会进入
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
//存储实现了BeanFactoryPostProcessor的对象
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
//存储实现了BeanDefinitionRegistryPostProcessor的对象
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
//1、处理通过api注册的beanFactoryPostProcessors对象的子类方法
// beanFactoryPostProcessors:传入通过api注册的beanFactoryPostProcessors对象
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
//如果实现的是子接口
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
//执行子接口的实现方法
registryProcessor.postProcessBeanDefinitionRegistry(registry);
//子接口实现方法执行完后添加集合中(等下统一执行一次父接口实现方法)
registryProcessors.add(registryProcessor);
}
else {
//不调用父接口的实现方法,直接存进集合
regularPostProcessors.add(postProcessor);
}
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
//存放当前需要执行的BeanDefinitionRegistryPostProcessor
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
//2、执行spring内置注册的几个BeanDefinition中实现了BeanDefinitionRegistryPostProcessors且implement PriorityOrdered的对象
// 即执行ConfigurationClassPostProcessor类的子类方法(实现了BeanDefinitionRegistryPostProcessor子接口)
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
//根据BeanDefinitionRegistryPostProcessor类型去BeanDefinitionMap中查询,存在则返回名字
//此时会去找到spring内置注册的几个BeanDefinition,
// 最后会返回一个名为org.springframework.context.annotation.internalConfigurationAnnotationProcessor(类型为ConfigurationClassPostProcessor)
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
//ConfigurationClassPostProcessor有实现PriorityOrdered接口,为true
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//加入到processedBeans(已处理集合)、currentRegistryProcessors(当前处理集合)
//调用getBean方法去实例化这个ConfigurationClassPostProcessor,并存到单例池中
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
//对currentRegistryProcessors集合里面的对象进行排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
//将当前处理currentRegistryProcessors集合加入到存放父接口对象集合registryProcessors中(合并)
//为什么要放到registryProcessors??(因为下面这行代码invokeBeanDefinitionRegistryPostProcessors(),只会执行其子接口方法,不会执行父接口方法)
registryProcessors.addAll(currentRegistryProcessors);
//遍历执行当前处理集合对象的子接口实现方法(注意由于这里只有ConfigurationClassPostProcessor,则执行了其子类方法)
//而ConfigurationClassPostProcessor的子类方法完成了对注入的对象扫描(@Component、@Bean)+@Import等注解的扫描,并加入BeanDefinitionMap中((此时未实例化为bean)
//所以执行完该方法BeanDefinitionMap中会出现我们注解注入的对象
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//执行完当前处理的集合后进行清除
currentRegistryProcessors.clear();
//3、执行spring内置注册的几个BeanDefinition+我们自己使用注解注入的BeanDefinition
// 其中实现了BeanDefinitionRegistryPostProcessor且implement Ordered的对象
//和上面的处理过程类似
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
//执行其子接口实现方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
//4、上面几种特殊情况的实现子接口的对象都处理完了,这里开始执行剩下通过注解注入bean的实现子接口的对象(处理@Compnent、@bean、@Import等注解注入的)
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
//这里reiterate进行循环是为了防止注入的bean中实现BeanDefinitionRegistryPostProcessors子接口的实现方法再次进行动态注入BeanDefinition
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) { //查看已处理集合是否存在,防止重复执行
//不存在,则进行实例化为bean,存进单例池。然后放进已处理集合
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
//执行子类方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
//执行1+2+3+4情况中(实现了子接口的)集合中的父类方法
//上面的1、2、3、4都是在处理实现了子接口BeanDefinitionRegistryPostProcessor的子类方法,到这里才统一执行其父类方法
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
//执行符合情况1+实现了父接口BeanFactoryPostProcessor的集合的父类方法
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
//5、处理除1、2、3、4情况外的所有实现了BeanFactoryPostProcessor
//获取所有实现父接口(排除1,因为情况1在上面已经执行了父类方法了)
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//实现了PriorityOrdered接口则实例化为bean,并存进单例池
//然后放进实现了PriorityOrdered的集合
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
//实现了Ordered+剩下的都不实例化为bean,直接加入集合
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
//排序并执行priorityOrderedPostProcessors集合的父类方法
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
//实例化orderedPostProcessorNames对应对象为bean,并进行排序+执行父类方法
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
//实例化剩下的对象为bean,并执行父类方法
// Finally, invoke all other BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}
可以通过调试看看各个情况下实例化情况、调用实现方法情况:
未执行情况1之前:
控制台也未打印任何信息
情况1执行完后:
控制台打印:
C --impl BeanDefinitionRegistryPostProcessor---by api ----Override postProcessBeanDefinitionRegistry
此时则表示C对象未被实例化为bean,但是已经执行了子类方法。
执行完情况2:
此时控制台打印信息:
C --impl BeanDefinitionRegistryPostProcessor---by api ----Override postProcessBeanDefinitionRegistry
此时使用了注解注入的a、d、h、i都被扫描到并实例化为bean,但是还没有去调用其实现方法。
注意:这里之所以能扫描到这些注解注入的对象,是内置的ConfigurationClassPostProcessor执行了其子类方法(扫描注解注入的对象,并将其实例化为bean,放入单例池中)
执行完情况3:
控制台:
C --impl BeanDefinitionRegistryPostProcessor---by api ----Override postProcessBeanDefinitionRegistry
I -- impl BeanDefinitionRegistryPostProcessor + PriorityOrdered---by @Component ----Override postProcessBeanDefinitionRegistry
执行完情况4:
控制台:
C --impl BeanDefinitionRegistryPostProcessor---by api ----Override postProcessBeanDefinitionRegistry
I -- impl BeanDefinitionRegistryPostProcessor + PriorityOrdered---by @Component ----Override postProcessBeanDefinitionRegistry
D -- impl BeanDefinitionRegistryPostProcessor--- by @Component ---- Override postProcessBeanDefinitionRegistry
F -- impl BeanDefinitionRegistryPostProcessor--- by BeanDefinition----Override postProcessBeanDefinitionRegistry
C--impl BeanDefinitionRegistryPostProcessor---by api ----Override postProcessBeanFactory
I --impl BeanDefinitionRegistryPostProcessor + PriorityOrdered--- by @Component ---- Override postProcessBeanFactory
D -- impl BeanDefinitionRegistryPostProcessor--- by @Component ---- Override postProcessBeanFactory
F-- impl BeanDefinitionRegistryPostProcessor---by BeanDefinition ---- Override postProcessBeanFactory
B--impl BeanFactoryPostProcessor---By api----Override postProcessBeanFactory
可以看到实现子类方法的对象都被实例化,并执行了子类方法+父类方法。还有通过api注入的都会在这个时候执行完。
执行完情况5:
控制台:
C --impl BeanDefinitionRegistryPostProcessor---by api ----Override postProcessBeanDefinitionRegistry
I -- impl BeanDefinitionRegistryPostProcessor + PriorityOrdered---by @Component ----Override postProcessBeanDefinitionRegistry
D -- impl BeanDefinitionRegistryPostProcessor--- by @Component ---- Override postProcessBeanDefinitionRegistry
F -- impl BeanDefinitionRegistryPostProcessor--- by BeanDefinition----Override postProcessBeanDefinitionRegistry
C--impl BeanDefinitionRegistryPostProcessor---by api ----Override postProcessBeanFactory
I --impl BeanDefinitionRegistryPostProcessor + PriorityOrdered--- by @Component ---- Override postProcessBeanFactory
D -- impl BeanDefinitionRegistryPostProcessor--- by @Component ---- Override postProcessBeanFactory
F-- impl BeanDefinitionRegistryPostProcessor---by BeanDefinition ---- Override postProcessBeanFactory
B--impl BeanFactoryPostProcessor---By api----Override postProcessBeanFactory
H -- impl BeanFactoryPostProcessor + PriorityOrdered--- by @Component----Override postProcessBeanFactory
A --impl BeanFactoryPostProcessor--- by @Component ---- Override postProcessBeanFactory
E -- impl BeanFactoryPostProcessor--- by BeanDefinition ---- Override postProcessBeanFactory
此时所有测试类的方法都会被调用了。
到这里我们通过debug验证了我们源码中注释的流程。所以我们可以粗略的得到一个结论,spring在处理实现了BeanFactoryPostProcessor/其子接口BeanDefinitionRegistryPostProcessor时,存在下面的执行实现方法的顺序
1)、子接口实现方法>>父接口方法
2)、api方式>>实现了PriorityOrdered接口>>通过注解注入>>动态注册BeanDefinition
(如果加上内置的,排序应该为api方式>>spring内置的实现了子接口的ConfigurationClassPostProcessor(完成扫描)>>实现了PriorityOrdered接口>>通过注解注入>>动态注册BeanDefinition)
3)、实现子接口比实现父接口更快执行
且可以推断出,spring实例化对象为bean的顺序为 :
-----------------------------------------------------------------------------------------------
此时我们就可以根据这个结论来解释前面的疑问,前面几篇文章存在下面的疑问:
1)、为什么 BeanFactoryPostProcessor接口(只能修改BeanDefinition,不能注册)(同14问)
2)、为什么不推荐BeanDefifinitionRegistryPostProcessor进行动态注册,而改使用ImportBeanDefifinitionRegistrar(同10问)
3)、为什么ImportBeanDefifinitionRegistrar要配合@Import注解使用,和@Compnent则不会调用其实现方法?
4)、ImportBeanDefifinitionRegistrar是在什么时机被调用的,怎么被回调的,为什么不能搭配@Compnent一起使用?
5)、mybatis是如何扩展spring的扫描器的?(扫描自定义注解或某个包下的类),而spring本身又是如何扫描的?
6)、FeactoryBean的工作原理是什么?
7)、BeanFactoryPostProcess的工作原理?怎么回调的?回调时机?本身是如何注入到spring中的?其子类的原理和作用?可以获取修改beandefinition,为什么不能注册?为什么有List<BeanFactoryPostProcess>这个集合?
8)、什么是单例池、BeanDefinitionMap、@import是如何工作的?
再通过上面的源码分析,我们会出现以下问题
9)、这些执行实现方法的顺序能不能变?
10)、BeanDefifinitionRegistryPostProcessor和ImportBeanDefifinitionRegistrar的区别(类似于第2)问)
11)、实现了PriorityOrderedPostProcessors的类为什么会先被实例化?
13)、BeanDefifinitionRegistryPostProcessor对beanDefinition的修改如何保证正确性?
14)、BeanFactoryPostProcessor为什么不开发注册BeanDefinition(实际可以实现,不过注入的不是个完整的Bean)?
15)、三个接口的作用、使用场景
16)、新版本的mybatis-spring怎么做集成的,和旧版本的使用ImportBeanDefifinitionRegistrar+@import+ FactoryBean??
----------------------------------------------------
9):从上面知道执行顺序api方式>>spring内置的实现了子接口的ConfigurationClassPostProcessor(完成扫描)>>实现了PriorityOrdered接口>>通过注解注入>>动态注册BeanDefinition,为什么api提供的要比spring内置的提前执行?
为了提高api方式的实现方法的执行优先级。
14)、其实BeanFactoryPostProcessor可以进行注册BeanDdefinition,只是无法注入完整的bean,我们看下下面的例子:
A类修改下进行注册Bd:
@Component
public class A implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//将beanFactory强转为子类对象DefaultListableBeanFactory,然后注册BeanDefinition
BeanDefinitionBuilder k = BeanDefinitionBuilder.genericBeanDefinition(K.class);
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
defaultListableBeanFactory.registerBeanDefinition("k",k.getBeanDefinition());
/*BeanDefinitionBuilder x = BeanDefinitionBuilder.genericBeanDefinition(X.class);
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
defaultListableBeanFactory.registerBeanDefinition("x",x.getBeanDefinition());*/
System.out.println("A --impl BeanFactoryPostProcessor--- by @Component ---- Override postProcessBeanFactory");
}
}
K类:
public class K implements BeanFactoryPostProcessor {
public K(){
System.out.println("create K BeanFactoryPostProcessor");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
System.out.println("k-p bd-A parent postProcessBeanFactory");
}
}
此时运行,会发现,K的构造方法可以被执行,但其父类实现方法不会被执行。
所以说即使BeanFactoryPostProcessor可以硬性的进行动态注册,但是会存在某些方法、注解(如@Bean)不生效。(spring中不会对api方式的类中的父接口对应的实现方法循环执行,即spring执行了实现了父接口的A的父类方法,但不会做循环对K的父类方法做执行,所以不会生效)
(但对于实现子类的会在情况4中进行循环执行实现方法,所以使用BeanDefifinitionRegistryPostProcessor进行注册则可以生效)
13)、BeanDefifinitionRegistryPostProcessor对beanDefinition的修改如何保证正确性?
我们先举一个例子,我们在D类中加入一个修改H的代码:
@Component
public class D implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("D -- impl BeanDefinitionRegistryPostProcessor--- by @Component ---- Override postProcessBeanFactory");
//log.debug("d-s scan parent postProcessBeanFactory");
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("D -- impl BeanDefinitionRegistryPostProcessor--- by @Component ---- Override postProcessBeanDefinitionRegistry");
//log.debug("d-s scan subclass postProcessBeanDefinitionRegistry register E F");
BeanDefinitionBuilder e = BeanDefinitionBuilder.genericBeanDefinition(E.class);
BeanDefinitionBuilder f= BeanDefinitionBuilder.genericBeanDefinition(F.class);
//动态获取到名为j的Beandefinition,然后修改其类型为L.class
AbstractBeanDefinition j = (AbstractBeanDefinition) registry.getBeanDefinition("j");
j.setBeanClass(L.class);
registry.registerBeanDefinition("e",e.getBeanDefinition());
registry.registerBeanDefinition("f",f.getBeanDefinition());
}
}
public class L implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("l-s scan parent postProcessBeanFactory");
}
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("l-s scan subclass postProcessBeanDefinitionRegistry register E F");
}
}
@Component
public class J implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("j-s scan parent postProcessBeanFactory");
}
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("j-s scan subclass postProcessBeanDefinitionRegistry register E F");
}
}
此时运行,我们预期的结果应该是j类的打印信息没有了,变成了L的打印信息。
D:\MyTools\Jdk\bin\java.exe "-javaagent:D:\MyTools\Idea\soft\IntelliJ IDEA 2022.2.1\lib\idea_rt.jar=10091:D:\MyTools\Idea\soft\IntelliJ IDEA 2022.2.1\bin" -Dfile.encoding=UTF-8 -classpath E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-demo\out\production\classes;D:\MyTools\Jdk\jre\lib\charsets.jar;D:\MyTools\Jdk\jre\lib\deploy.jar;D:\MyTools\Jdk\jre\lib\ext\access-bridge-64.jar;D:\MyTools\Jdk\jre\lib\ext\cldrdata.jar;D:\MyTools\Jdk\jre\lib\ext\dnsns.jar;D:\MyTools\Jdk\jre\lib\ext\jaccess.jar;D:\MyTools\Jdk\jre\lib\ext\jfxrt.jar;D:\MyTools\Jdk\jre\lib\ext\localedata.jar;D:\MyTools\Jdk\jre\lib\ext\nashorn.jar;D:\MyTools\Jdk\jre\lib\ext\sunec.jar;D:\MyTools\Jdk\jre\lib\ext\sunjce_provider.jar;D:\MyTools\Jdk\jre\lib\ext\sunmscapi.jar;D:\MyTools\Jdk\jre\lib\ext\sunpkcs11.jar;D:\MyTools\Jdk\jre\lib\ext\zipfs.jar;D:\MyTools\Jdk\jre\lib\javaws.jar;D:\MyTools\Jdk\jre\lib\jce.jar;D:\MyTools\Jdk\jre\lib\jfr.jar;D:\MyTools\Jdk\jre\lib\jfxswt.jar;D:\MyTools\Jdk\jre\lib\jsse.jar;D:\MyTools\Jdk\jre\lib\management-agent.jar;D:\MyTools\Jdk\jre\lib\plugin.jar;D:\MyTools\Jdk\jre\lib\resources.jar;D:\MyTools\Jdk\jre\lib\rt.jar;D:\MyTools\gradle\gradle-5.6.4-bin\rep\caches\modules-2\files-2.1\org.projectlombok\lombok\1.18.22\9c08ea24c6eb714e2d6170e8122c069a0ba9aacf\lombok-1.18.22.jar;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-core\build\libs\spring-cglib-repack-3.3.0.jar;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-core\build\libs\spring-objenesis-repack-3.1.jar;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-context\out\production\classes;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-context\out\production\resources;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-aop\out\production\classes;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-aop\out\production\resources;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-beans\out\production\classes;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-beans\out\production\resources;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-expression\out\production\classes;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-expression\out\production\resources;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-core\out\production\classes;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-core\out\production\resources;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-jcl\out\production\classes;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-jcl\out\production\resources com.spring.demo.invokeBeanFactoryPostProcessors.ApplicationContextTest -Dfile.encoding=utf-8
C --impl BeanDefinitionRegistryPostProcessor---by api ----Override postProcessBeanDefinitionRegistry
I -- impl BeanDefinitionRegistryPostProcessor + PriorityOrdered---by @Component ----Override postProcessBeanDefinitionRegistry
D -- impl BeanDefinitionRegistryPostProcessor--- by @Component ---- Override postProcessBeanDefinitionRegistry
j-s scan subclass postProcessBeanDefinitionRegistry register E F
F -- impl BeanDefinitionRegistryPostProcessor--- by BeanDefinition----Override postProcessBeanDefinitionRegistry
C--impl BeanDefinitionRegistryPostProcessor---by api ----Override postProcessBeanFactory
I --impl BeanDefinitionRegistryPostProcessor + PriorityOrdered--- by @Component ---- Override postProcessBeanFactory
D -- impl BeanDefinitionRegistryPostProcessor--- by @Component ---- Override postProcessBeanFactory
j-s scan parent postProcessBeanFactory
F-- impl BeanDefinitionRegistryPostProcessor---by BeanDefinition ---- Override postProcessBeanFactory
B--impl BeanFactoryPostProcessor---By api----Override postProcessBeanFactory
H -- impl BeanFactoryPostProcessor + PriorityOrdered--- by @Component----Override postProcessBeanFactory
A --impl BeanFactoryPostProcessor--- by @Component ---- Override postProcessBeanFactory
E -- impl BeanFactoryPostProcessor--- by BeanDefinition ---- Override postProcessBeanFactory
Process finished with exit code 0
可打印结果却发现修改BeanDefinition的代码没有生效,原因在于D类和J的实例化为bean优先级一样,所以去D修改J时,J已经被实例化为bean了,此时修改BeanDefinition已经没用了。
我们可以从上面的代码找到一个方法,就是在情况2-3之间,会对注解方式的对象转为BeanDefiniton对象并存进BeanDefinitionMap中,此时还没有实例化为bean,所以我们可以在这个时机通过提升修改BeanDefinition的代码执行优先级,即把修改的代码放到实现了PriorityOrdered接口的I类上:
此时我们在I中对J进行修改:
@Component
public class I implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("I --impl BeanDefinitionRegistryPostProcessor + PriorityOrdered--- by @Component ---- Override postProcessBeanFactory");
//log.debug("i-s scan parent postProcessBeanFactory PriorityOrdered");
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("I -- impl BeanDefinitionRegistryPostProcessor + PriorityOrdered---by @Component ----Override postProcessBeanDefinitionRegistry");
//log.debug("i-s scan subclass postProcessBeanDefinitionRegistry PriorityOrdered");
AbstractBeanDefinition j = (AbstractBeanDefinition) registry.getBeanDefinition("j");
j.setBeanClass(L.class);
// BeanDefinitionBuilder x= BeanDefinitionBuilder.genericBeanDefinition(X.class);
// registry.registerBeanDefinition("x",x.getBeanDefinition());
}
@Override
public int getOrder() {
return 0;
}
}
控制台:
D:\MyTools\Jdk\bin\java.exe "-javaagent:D:\MyTools\Idea\soft\IntelliJ IDEA 2022.2.1\lib\idea_rt.jar=10192:D:\MyTools\Idea\soft\IntelliJ IDEA 2022.2.1\bin" -Dfile.encoding=UTF-8 -classpath E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-demo\out\production\classes;D:\MyTools\Jdk\jre\lib\charsets.jar;D:\MyTools\Jdk\jre\lib\deploy.jar;D:\MyTools\Jdk\jre\lib\ext\access-bridge-64.jar;D:\MyTools\Jdk\jre\lib\ext\cldrdata.jar;D:\MyTools\Jdk\jre\lib\ext\dnsns.jar;D:\MyTools\Jdk\jre\lib\ext\jaccess.jar;D:\MyTools\Jdk\jre\lib\ext\jfxrt.jar;D:\MyTools\Jdk\jre\lib\ext\localedata.jar;D:\MyTools\Jdk\jre\lib\ext\nashorn.jar;D:\MyTools\Jdk\jre\lib\ext\sunec.jar;D:\MyTools\Jdk\jre\lib\ext\sunjce_provider.jar;D:\MyTools\Jdk\jre\lib\ext\sunmscapi.jar;D:\MyTools\Jdk\jre\lib\ext\sunpkcs11.jar;D:\MyTools\Jdk\jre\lib\ext\zipfs.jar;D:\MyTools\Jdk\jre\lib\javaws.jar;D:\MyTools\Jdk\jre\lib\jce.jar;D:\MyTools\Jdk\jre\lib\jfr.jar;D:\MyTools\Jdk\jre\lib\jfxswt.jar;D:\MyTools\Jdk\jre\lib\jsse.jar;D:\MyTools\Jdk\jre\lib\management-agent.jar;D:\MyTools\Jdk\jre\lib\plugin.jar;D:\MyTools\Jdk\jre\lib\resources.jar;D:\MyTools\Jdk\jre\lib\rt.jar;D:\MyTools\gradle\gradle-5.6.4-bin\rep\caches\modules-2\files-2.1\org.projectlombok\lombok\1.18.22\9c08ea24c6eb714e2d6170e8122c069a0ba9aacf\lombok-1.18.22.jar;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-core\build\libs\spring-cglib-repack-3.3.0.jar;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-core\build\libs\spring-objenesis-repack-3.1.jar;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-context\out\production\classes;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-context\out\production\resources;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-aop\out\production\classes;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-aop\out\production\resources;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-beans\out\production\classes;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-beans\out\production\resources;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-expression\out\production\classes;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-expression\out\production\resources;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-core\out\production\classes;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-core\out\production\resources;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-jcl\out\production\classes;E:\09Project\spring\spring-framework-5.2.x\spring-framework-5.2.x\spring-jcl\out\production\resources com.spring.demo.invokeBeanFactoryPostProcessors.ApplicationContextTest -Dfile.encoding=utf-8
C --impl BeanDefinitionRegistryPostProcessor---by api ----Override postProcessBeanDefinitionRegistry
I -- impl BeanDefinitionRegistryPostProcessor + PriorityOrdered---by @Component ----Override postProcessBeanDefinitionRegistry
D -- impl BeanDefinitionRegistryPostProcessor--- by @Component ---- Override postProcessBeanDefinitionRegistry
l-s scan subclass postProcessBeanDefinitionRegistry register E F
F -- impl BeanDefinitionRegistryPostProcessor--- by BeanDefinition----Override postProcessBeanDefinitionRegistry
C--impl BeanDefinitionRegistryPostProcessor---by api ----Override postProcessBeanFactory
I --impl BeanDefinitionRegistryPostProcessor + PriorityOrdered--- by @Component ---- Override postProcessBeanFactory
D -- impl BeanDefinitionRegistryPostProcessor--- by @Component ---- Override postProcessBeanFactory
l-s scan parent postProcessBeanFactory
F-- impl BeanDefinitionRegistryPostProcessor---by BeanDefinition ---- Override postProcessBeanFactory
B--impl BeanFactoryPostProcessor---By api----Override postProcessBeanFactory
H -- impl BeanFactoryPostProcessor + PriorityOrdered--- by @Component----Override postProcessBeanFactory
A --impl BeanFactoryPostProcessor--- by @Component ---- Override postProcessBeanFactory
E -- impl BeanFactoryPostProcessor--- by BeanDefinition ---- Override postProcessBeanFactory
此时发现修改成功了。
这个问题告诉我们,可以利用实例化为bean的优先级去排查修改不生效的操作,也可以利用其优先级去实现修改的操作(实现了PriorityOrdered接口去提升优先级)。
所以在BeanDefifinitionRegistryPostProcessor中修改BeanDefinition需要注意其不生效的情况以及解决方法。
11)、实现了PriorityOrdered接口的(PriorityOrderedPostProcessors集合)为什么会先被实例化?
和上面13)问一样,为了提供一个优先级的设计。
10)、BeanDefifinitionRegistryPostProcessor和ImportBeanDefifinitionRegistrar的区别
从上面知道顺序api方式>>spring内置的实现了子接口的ConfigurationClassPostProcessor(完成扫描)>>实现了PriorityOrdered接口>>通过注解注入>>动态注册BeanDefinition。
而我们对于ImportBeanDefifinitionRegistrar实现方法的执行时机是比BeanDefifinitionRegistryPostProcessor前的(注意invokeBeanFactoryPostProcessors方法中会实例化实现了ImportBeanDefifinitionRegistrar的类,但实例化的是普通的对象,不会实例化为bean)
(1)ImportBeanDefifinitionRegistrar的实现方法的执行时机优先于BeanDefifinitionRegistryPostProcessor,较高的优先级有利于对一些BeanDefinition做修改时的正确性。
(2)实现ImportBeanDefifinitionRegistrar接口的实现方法,可以多返回一个
AnnotationMetadata参数,用于获取一些元数据(例如注解信息、注解中的扫描包路径等配置信息)
这样会比BeanDefifinitionRegistryPostProcessor更加丰富。
这就又回到了优先级的问题上,所以在@Compnent+ImportBeanDefifinitionRegistrar的实现方法不会生效,因为spring不会去处理@Compnent+ImportBeanDefifinitionRegistrar的组合(只是当成一个普通的Bean进行注入,不会执行其实现方法),这就解释了问题3、4)。---这点尚需验证。
@Import大部分情况是可以注入bean的,但要是注入的类实现了ImportBeanDefifinitionRegistrar则注入不了。(实现ImportBeanDefifinitionRegistrar更多的是为了去调用其实现方法去动态注册BeanDefinition的功能)
所以我们可以大概知道在ImportBeanDefifinitionRegistrar方法中只对
ConfigurationClassPostProcessor等内置的+@Compnent注册的类+实现了PriorityOrdered的类+实现了子类BeanFactoryPostProcessor、父类BeanDefifinitionRegistryPostProcessor的。。。。
这里实现了ImportBeanDefifinitionRegistrar+@Import、api进来的类都没实例化为bean
15)、三个接口的作用、使用场景
BeanFactoryPostProcessor的作用和使用场景
(1)、可以用来修改BeanDefinition等容器全局配置
(2)、可以用来配置忽视自动注入(注意:只有注入模型是自动注入才能忽视生效)(后面再举例说明)?????????????????????
BeanDefinitionRegistryPostProcessor、ImportBeanDefifinitionRegistrar:
(1)、第三方集成spring中,使用ImportBeanDefifinitionRegistrar进行动态注册BeanDefinition等操作
执行时机ImportBeanDefifinitionRegistrar》》BeanDefinitionRegistryPostProcessor》》BeanFactoryPostProcessor
还有其他????
16)、新版本的mybatis-spring怎么做集成的,和旧版本的使用ImportBeanDefifinitionRegistrar+@import+ FactoryBean??
--------------------------------------------
至此我们剩下的问题应该就剩:
5)、mybatis是如何扩展spring的扫描器的?(扫描自定义注解或某个包下的类),而spring本身又是如何扫描的?
6)、FeactoryBean的工作原理是什么?
8)、什么是单例池、BeanDefinitionMap、@import是如何工作的?
16)、新版本的mybatis-spring怎么做集成的,和旧版本的使用ImportBeanDefifinitionRegistrar+@import+ FactoryBean??
对于扫描器会在下篇进行讲解,其他问题会带着继续往下讲
------------------------------------------------------
总结:该篇文章中通过对invokeBeanFactoryPostProcessors方法源码进行分析,发现通过不同方式注入的代码执行优先级存在差异,从而解释了BeanFactoryPostProcessor与子接口BeanDefinitionRegistryPostProcessor的各种差异,也解释了前面为何不推荐这两者,而去使用ImportBeanDefifinitionRegistrar进行动态注册BeanDefinition。通过前面的学习,我们也大概知道了BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor、ImportBeanDefifinitionRegistrar三个接口的大概作用和执行时机。
下面我开始进行解析spring的扫描机制: