BeanFactoryProcessor扩展点

520 阅读5分钟

这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战

BeanFactoryPostProcessorspring中一个很重要的扩展点,它与BeanPostProcessor长相类似,触发点略有不同。BeanFactoryPostProcessor的作用时期是在所有bean实例化之前。所以它的作用是加载BeanDefinition。或者可以动态的修改或者是新增BeanDefinition

类图

BeanFactoryPostProcessor有一个扩展接口,这个扩展接口的方法会优先与BeanFactoryPostProcessor的方法执行。

BeanFactoryPostProcessor类图.png

源码

​ 还是从spring的核心方法refresh入手。其中的invokeBeanFactoryPostProcessors(beanFactory);就是用来处理BeanFactoryPostProcessorspringrefresh在之前的文章中有介绍,这边就不展开。 1.调用BeanFactoryPostProcessor ---> (在这里执行!!!)

@Override
public void refresh() throws BeansException, IllegalStateException {
    // ...
    invokeBeanFactoryPostProcessors(beanFactory);
    // ...
}

核心的处理方法在PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors,源码处已有一些注释。这里简单描述一下整个流程。

第一步:参数中传递进来的 beanFactoryPostProcessors,由上述可知,这里可能是BeanDefinitionRegistryPostProcessor也可能是BeanFactoryPostProcessor的实现类。所以定义两个集合regularPostProcessorsregistryProcessors用于将二者分离开。这里会执行参数中传递进来的BeanDefinitionRegistryPostProcessor类型的接口。(在springboot中,可以在启动类的启动方法中添加)

第二步:获取容器中所有的BeanDefinitionRegistryPostProcessor,挑选出包含实现了PriorityOrdered接口的类,根据特定的排序规则进行排序后逐一执行。(在默认的情况下,这里仅会获取到ConfigurationClassPostProcessor,这里类的作用是处理配置类,将配置类[也就是开发者标记@Configuration@Component@ImportSelector等等]添加到容器中。)

第三步:获取容器中所有的BeanDefinitionRegistryPostProcessor,挑选出包含实现了Ordered接口的类,过滤执行过BeanDefinitionRegistryPostProcessor(若某个接口同时实现OrderedPriorityOrdered,则应该在第二步中执行),根据特定的排序规则进行排序后逐一执行。

第四步:获取容器中所有的BeanDefinitionRegistryPostProcessor,过滤已经执行过的,将剩下未执行的所有类,根据特定的排序规则进行排序后逐一执行。(这里使用死循环的原因:可能出现套娃情况,某个BeanDefinitionRegistryPostProcessor的实现方法中又创建了一个新的BeanDefinitionRegistryPostProcessor。)

以上便已经执行了容器中所有BeanDefinitionRegistryPostProcessor的扩展点。接下来就是执行BeanFactoryPostPostProcessor扩展点。

第五步:执行上述所有步骤中的BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor的实现接口。(就是扩展接口中的扩展方法已经都执行完了,在这个地方统一执行父接口中的实现方法。)

第六步:执行参数中传递进来的beanFactoryPostProcessors中仅实现BeanFactoryPostProcessor的实现接口。

第七步:(BeanFactoryPostPostProcessor的执行比较简单,用一步概括),获取容器中所有实现了BeanFactoryPostProcessor的类,将它们分为三类PriorityOrderedOrdered、和没有实现这两个接口的。然后分别根据排序规则进行排序后逐一执行。

  1. 执行BeanDefinitionRegistryPostProcessor的扩展点

    1.1 执行参数beanFactoryPostProcessors中是BeanDefinitionRegistryPostProcessor的实现类的扩展点

    1.2 执行spring容器中的BeanDefinitionRegistryPostProcessor的实现且依次@PriorityOrdered、@Ordered

    1.3执行容器中还存在BeanDefinitionRegistryPostProcessor实现但未加入已执行集合(registryProcessors)中的实现类

  2. 执行BeanDefinitionPostProcessor的扩展点

    2.1执行非直接实现BeanDefinitionRegistryPostProcessor集合(registryProcessors)的BeanFactoryPostProcessor的扩展点

    2.2执行直接实现BeanFactoryPostProcessor集合(regularPostProcessors)的BeanFactoryPostProcessor的扩展点(这个集合中若存在元素, 则是开发者通过调用参数携带进来, 在第一步骤执行是分离出来)

    2.3执行spring容器中还未执行的BeanFactoryPostProcessor、顺序依次为@PriorityOrdered@Ordered、最后是没有标记前者两注解的BeanFactoryPostProcessor的实现类。beanFactoryPostProcessors这个是自定义的beanFactoryPostProcessors, 默认是空的, 除非自己扩展。

①.处理过的BeanDefinitionRegistryPostProcessors类型的bean名字集合
②.常规postProcessor(直接实现BeanFactoryPostProcessor的实现类)集合
③.registryProcessor(非直接实现BeanFactoryPostProcessor的实现类)且已经调用过扩展点的集合
④.BeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor的父接口, 执行beanFactoryPostProcessors中的BeanDefinitionRegistryPostProcessor并将执行过后的BeanDefinitionRegistryPostProcessor放置在registryProcessors, 将未执行的BeanFactoryPostProcessor添加到regularPostProcessors
⑤.调用BeanDefinitionRegistryPostProcessor扩展点
⑥.直接实现了BeanFactoryPostProcessor接口的实现
⑦.放内部的BeanDefinitionRegistryPostProcessor后置处理器
⑧.首先, 调用实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessors(若没有改造或者二次开发过, 此处只会返回ConfigurationClassPostProcessorConfigurationClassPostProcessor类的作用是加载配置类)
⑨.调用processedBeans中没有标记过的BeanDefinitionRegistryPostProcessors这个while循环是由于可能出现套娃的情况: 比如A类实现了BeanDefinitionRegistryPostProcessor, 在调用A的 postProcessBeanDefinitionRegistry中又添加了一个BeanDefinitionRegistryPostProcessor类B。
⑩.不要在此处初始化 FactoryBeans:我们需要保留所有未初始化的常规bean,让 bean 工厂后处理器应用于它们!

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
	// ①
	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);
			}
		}
		// ⑦
		List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

		// ⑧
		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);
			}
		}
		registryProcessors.addAll(currentRegistryProcessors);
		// 执行BeanDefinitionRegistryPostProcessors扩展点
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
		currentRegistryProcessors.clear();

		// 调用仅实现了Ordered接口的BeanDefinitionRegistryPostProcessors
		postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
		for (String ppName : postProcessorNames) {
			// 过滤调用过的processedBean
			if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                            // ...
			}
		}

		// ⑨.
		boolean reiterate = true;
		while (reiterate) {
			reiterate = false;
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName)) {
                                    // ...
				}
			}
		}
	} 

	// ⑩
	String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
}

例子

​ 从spring的生命周期看BeanFactoryPostProcessor的执行时机就是在BeanPostProcessor注册之前,甚至可以说是在大部分的bean注入之前。但若大量使用BeanFactoryPostProcessor进行扩展,若有重叠区域,则需考虑执行的先后顺序。比如后期的扩展是否需要控制新的BeanFactoryPostProcessor要在旧BeanFactoryPostProcessor之前或者之后?这个执行顺序是一个很容易忽略的关键点(自定义的BeanFactoryPostProcessor可以通过实现Order接口控制执行顺序)

实例1

​ 可以通过BeanDefinitionRegistryPostProcessor修改BeanDefinition,比如在业务场景中有非常多的地方使用的是名称注入的方式,现要让这个名称注入容器中的类由新类,替换旧类。 扫描项目路径下的旧类,进行class替换,并使其指向新类。

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
      BeanDefinition beanDefinition = registry.getBeanDefinition("roomService");
      beanDefinition.setBeanClassName("cn.com.xiaocainiaoya.service.NewRoomService");
    }
}

实例2

springframwork的扫描工作中比较核心的类ConfigurationClassPostProcessor,这个类的作用就是扫描配置类,扫描指定路径下的各种配置注解@ConfigurationComponentComponentScan等等。将这些类解析后添加到BeanDefinition中。

以下方法的主要作用为从注册表中的配置类派生进一步的bean定义,简单说根据beanDefinition将配置类添加到spring容器中。

执行的顺序为:

  1. 完成扫描

  2. 对配置类的定义,完成对配置类的标记

  3. import的处理

    3.1 ImportSelector(在springboot中自动装配典型使用)

    3.2 ImportBeanDefinitionRegistrar(在mybatis中典型使用)

    3.3 普通类:没有任何特殊注解或者加了@Import

    3.4 ImportResource

  4. @Bean的处理

  5. 接口中的@bean

  6. @PropertySource的处理

  7. 内部类的处理

  8. 父类的处理

说明:
①.表示此registry里的BeanDefinition收集动作,避免再重复收集此registry
②.根据配置类,收集到所有的bd信息,并且做出mark标注:是Full模式还是Lite模式

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	// ...

	// ①
	this.registriesPostProcessed.add(registryId);

	// ②
	processConfigBeanDefinitions(registry);
}

注意事项

BeanFactoryPostProcessor算是spring给予开发者很高的权限去处理BeanDefinitions,但使用的过程中还需遵守spring的规范,不可将bean实例化,即不可在BeanFactoryPostProcessor中触发bean实例化的操作。比如:
1.这个getBeansOfType调用会触发getBean方法,会导致Bean提前注入,而在生命周期的这个节点自动注入的BeanPostProcessor还没有注入,还不会作用在bean的创建过程中,所以会导致 RoomService的属性注入会失效。

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
      // 1.
      Map<String, RoomService> map = beanFactory.getBeansOfType(RoomService.class);
    }
}

所以,在BeanFactoryPostProcessor的使用中切记要确保不会触发Bean的提前实例化。