Spring Boot-11-refresh()之invokeBeanFactoryPostProcessors()扫描bean

本章源码基于Spring Boot 2.2.8

一、背景

这篇文章讲refresh()方法里的invokeBeanFactoryPostProcessors()方法
经典入口:org.springframework.context.support.AbstractApplicationContext#refresh()
AbstractApplicationContext 始自2001.1.21
初代设计就有了
org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors()
官方对这个方法的说明如下:
实例化并调用所有注册过的BeanFactoryPostProcessor beans,如果有顺序,会按照顺序调用,必须在单例实例化操作前被调用。

二、invokeBeanFactoryPostProcessors()的作用

在解读源码的时候,有一个致命的缺点就是枯燥且漫无目的,所以我先给出这段代码的作用,让大家明白他的重要性,并给大家一个目标去探索,这样会更加愉快。
那这个方法执行完成后,到底做了什么?
答案在这些BeanFactoryPostProcessor身上,BeanDefinitionRegistryPostProcessor这个处理器就是将BeanDefinition注册到容器的,所以我们可以看到,在没有第三方扩展BeanDefinitionRegistryPostProcessor情况下,这个方法执行后,所有的bean的BeanDefinition就都生成了。Spring的bean就是在这里被全部扫描出来的。

三、源码解读

invokeBeanFactoryPostProcessors()如下:我们主要关注上面一句,下面的一段是根据具体情况添加 AspectJ 支持,这里不做任何解释。
org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors()

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

	// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
	// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
	if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}
}

这里将逻辑全都委托出去了,大家看到了Delegate方式的使用?就是另外一个封装类而已,同学们可以尝试在自己代码中在合适场景下用这种风格来封装代码。

要研究BeanFactoryPostProcessor的调用,必须要知道有哪些BeanFactoryPostProcessor
AbstractApplicationContext中有个成员变量用来保存refresh时要执行的BeanFactoryPostProcessor,定义如下:
org.springframework.context.support.AbstractApplicationContext#beanFactoryPostProcessors

private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();

同时有个添加的成员的方法,我们只要断点守住这个方法,就能轻松的知道BeanFactoryPostProcessor的来源?但是事情并不是想象的那么简单,因为BeanFactoryPostProcessor不仅存在于AbstractApplicationContext的成员变量中,还存在于容器中。
org.springframework.context.support.AbstractApplicationContext#addBeanFactoryPostProcessor()

@Override
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
	Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
	this.beanFactoryPostProcessors.add(postProcessor);
}

运行时,Spring添加了3个BeanFactoryPostProcessor,分别是:
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor (implements BeanDefinitionRegistryPostProcessor, PriorityOrdered)
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer.ConfigurationWarningsPostProcessor (implements PriorityOrdered, BeanDefinitionRegistryPostProcessor)
org.springframework.boot.context.config.ConfigFileApplicationListener.PropertySourceOrderingPostProcessor (implements BeanFactoryPostProcessor, Ordered)
可以看到这三个类都是Spring Boot特有的,全都使用了内部类。第1个是autoconfigure模块下,后面2个后Spring Boot context模块下,也就是说,以前Spring项目是没有这些的。
前2个实现了BeanDefinitionRegistryPostProcessor这个在下面的代码中涉及到了,所以先要说明一下,官方的说明是:
BeanDefinitionRegistryPostProcessor是对标准SPI BeanFactoryPostProcessor的扩展,他允许在常规BeanFactoryPostProcessor(非BeanDefinitionRegistryPostProcessor)检测发生前注册一些更早的BeanDefinition。特别地,BeanDefinitionRegistryPostProcessor注册的BeanDefinition可能反过来会注册BeanFactoryPostProcessor实例。
大致可以猜到了,BeanDefinitionRegistryPostProcessor是用来注册BeanDefinition的,且他在BeanFactoryPostProcessors中优先处理的。
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor#postProcessBeanDefinitionRegistry()方法做了2件事:
1、注册一个BeanDefinition:org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer.SharedMetadataReaderFactoryBean
2、给internalConfigurationAnnotationProcessor对应的BeanDefinition添加属性metadataReaderFactory:value
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer.ConfigurationWarningsPostProcessor#postProcessBeanDefinitionRegistry()方法做了检查和warn的打印,不必多说。

下面来看看invokeBeanFactoryPostProcessors()方法的逻辑,因为要执行的BeanFactoryPostProcessor会手动添加,具体逻辑:
这里一开始就判断当前使用的BeanFactory是不是BeanDefinitionRegistry类型,难道还有BeanFactory可以不使用BeanDefinitionRegistry?实际上,Spring容器都必须持有BeanDefinition,也就是必须实现BeanDefinitionRegistry接口,这里做判断只是为了更加编程更加严谨而已。步骤如下:
1、先处理Spring内部注册的,在AbstractApplicationContext中的成员变量的BeanFactoryPostProcessor,然后通过遍历将这些BeanFactoryPostProcessor划分为2类,一类是BeanDefinitionRegistryPostProcessor,另一类是非BeanDefinitionRegistryPostProcessor,并在遍历的时候,执行了BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry(),此时是可能往容器中添加一些BeanFactoryPostProcessor,这一步是种子操作
2、上面获取到的BeanFactoryPostProcessor都是Spring内部定义的,且不是在BeanFactory容器中的,接下来就从BeanFactory中获取所有BeanDefinitionRegistryPostProcessor,然后遍历获取到的BeanDefinitionRegistryPostProcessor,挑出是PriorityOrdered类型的,排序,执行。这一步是非常重要的,因为org.springframework.context.annotation.ConfigurationClassPostProcessor这个类就在容器中,他会处理所有@Configuration的类,然后注册到容器中。这一步执行过后,会有很多BeanDefinition注册到容器中了
3、由于执行BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry()可能引入新的BeanDefinitionRegistryPostProcessor,比如tk.mybatis.spring.mapper.MapperScannerConfigurer这个类就会被引入,所以继续从容器中取所有的BeanDefinitionRegistryPostProcessor,挑出是Ordered类型的,排序,执行(判断是前面没有执行过的processor)。
4、死循环逻辑{从容器中获取BeanDefinitionRegistryPostProcessor,排序,执行},知道获取到的BeanDefinitionRegistryPostProcessor全都被执行过。
5、执行所有BeanDefinitionRegistryPostProcessor且BeanFactoryPostProcessor的BeanFactoryPostProcessor#postProcessBeanFactory()方法
6、执行AbstractApplicationContext成员变量中BeanFactoryPostProcessor的BeanFactoryPostProcessor#postProcessBeanFactory()方法
7、执行到这一步,剩下的BeanFactoryPostProcessor就是容器中非BeanDefinitionRegistryPostProcessor且是BeanFactoryPostProcessor的类了,然后按照PriorityOrdered、Ordered、非前2者的顺序执行。
org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()

public static void invokeBeanFactoryPostProcessors(
		ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

	// Invoke BeanDefinitionRegistryPostProcessors first, if any.
	Set<String> processedBeans = new HashSet<>();

	if (beanFactory instanceof BeanDefinitionRegistry) {
		BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
		List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
		List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

		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.
		List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

		// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
		for (String ppName : postProcessorNames) {
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
				processedBeans.add(ppName);
			}
		}
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		registryProcessors.addAll(currentRegistryProcessors);
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
		currentRegistryProcessors.clear();

		// 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();

		// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
		boolean reiterate = true;
		while (reiterate) {
			reiterate = false;
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName)) {
					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.
		invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
		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!
	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)) {
			priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
		}
		else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
			orderedPostProcessorNames.add(ppName);
		}
		else {
			nonOrderedPostProcessorNames.add(ppName);
		}
	}

	// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
	invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

	// 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);

	// 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();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值