一文吃透Spring Boot扩展之BeanFactoryPostProcessor

概述

BeanFactoryPostProcessor 是Spring中一个相当重要的扩展点,扩展点就是能让我们在Spring容器以及Bean生命周期的各个阶段中可以进行修改扩展。

什么是BeanFactoryPostProcessor

BeanFactoryPostProcessor , 翻译过来大致是Bean的工厂处理器,顾名思义,可以理解为它对Bean工厂中Bean定义( BeanDefintion )进行修改, 它的执行时机:BeanFactory标准初始化之后,所有的Bean定义已经被加载,但标准Bean的实例还没被创建(不包括 BeanFactoryPostProcessor 类型)。该方法通常用于修改bean的定义,Bean的属性值等,甚至可以在此快速初始化Bean。

而另外一个相关的扩展接口的 BeanDefinitionRegistryPostProcessor ,继承自 BeanFactoryPostProcessor ,所有的Bean定义即将被加载,但Bean的实例还没被创建时,也就是说, BeanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry 方法执行时机先于 BeanFactoryPostProcessor 的 postProcessBeanFactory 方法。

区别于一个很类似的扩展接口 BeanPostProcessor , 它的执行时机实在Bean初始化前后,添加一些自己想要的逻辑。

小结一下,上面关联的扩展接口执行顺序如下:1. BeanDefinitionRegistryPostProcessor ,2. BeanFactoryPostProcessor ,3. BeanPostProcessor 。而 BeanFactoryPostProcessor 主要是在标准的 BeanDefinition 已经准备完毕,可以去修改已有的 BeanDefinition 的相关属性等。

如何使用BeanFactoryPostProcessor

  1. 新建一个测试bean
@Data
@Component
public class Student {

    @Value("${user.username:alvin}")
    private String username;

    @Value("${user.age:12}")
    private int age;
}
复制代码
  1. 新建处理器实现 BeanFactoryPostProcessor
@Component
@Slf4j
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        log.info("******************** TestBeanFactoryPostProcessor#postProcessBeanFactory ****************");
        log.info("******************** bean的数量:[{}] ****************", beanFactory.getBeanDefinitionCount());
        // 修改bean definition属性信息
        BeanDefinition userBeanDef = beanFactory.getBeanDefinition("student");
        userBeanDef.getPropertyValues().add("username", "cxw");

        // 快速初始化Bean
        User user = (User)beanFactory.getBean("student");
        log.info("student name: [{}]", user.getUsername());
    }
}
复制代码
  1. 验证结论
一文吃透Spring Boot扩展之BeanFactoryPostProcessor_第1张图片

bean的属性被成功被修改了。

源码解析

接口定义

/**
 * Factory hook that allows for custom modification of an application context's
 * bean definitions, adapting the bean property values of the context's underlying
 * bean factory.
 *
 * 

Useful for custom config files targeted at system administrators that * override bean properties configured in the application context. See * {@link PropertyResourceConfigurer} and its concrete implementations for * out-of-the-box solutions that address such configuration needs. * *

A {@code BeanFactoryPostProcessor} may interact with and modify bean * definitions, but never bean instances. Doing so may cause premature bean * instantiation, violating the container and causing unintended side-effects. * If bean instance interaction is required, consider implementing * {@link BeanPostProcessor} instead. * *

Registration

*

An {@code ApplicationContext} auto-detects {@code BeanFactoryPostProcessor} * beans in its bean definitions and applies them before any other beans get created. * A {@code BeanFactoryPostProcessor} may also be registered programmatically * with a {@code ConfigurableApplicationContext}. * *

Ordering

*

{@code BeanFactoryPostProcessor} beans that are autodetected in an * {@code ApplicationContext} will be ordered according to * {@link org.springframework.core.PriorityOrdered} and * {@link org.springframework.core.Ordered} semantics. In contrast, * {@code BeanFactoryPostProcessor} beans that are registered programmatically * with a {@code ConfigurableApplicationContext} will be applied in the order of * registration; any ordering semantics expressed through implementing the * {@code PriorityOrdered} or {@code Ordered} interface will be ignored for * programmatically registered post-processors. Furthermore, the * {@link org.springframework.core.annotation.Order @Order} annotation is not * taken into account for {@code BeanFactoryPostProcessor} beans. * * @author Juergen Hoeller * @author Sam Brannen * @since 06.07.2003 * @see BeanPostProcessor * @see PropertyResourceConfigurer */ @FunctionalInterface public interface BeanFactoryPostProcessor { /** * Modify the application context's internal bean factory after its standard * initialization. All bean definitions will have been loaded, but no beans * will have been instantiated yet. This allows for overriding or adding * properties even to eager-initializing beans. * @param beanFactory the bean factory used by the application context * @throws org.springframework.beans.BeansException in case of errors */ void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; } 复制代码

接口的注释很清楚的说明了它的作用和细节,大致有下面几点:

PropertyResourceConfigurer

执行流程

一文吃透Spring Boot扩展之BeanFactoryPostProcessor_第2张图片

其中核心逻辑是 PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors 方法,该方法的前面部分逻辑主要是处理 BeanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry 方法,也就是想BeanDefinition注册中中心添加新的BeanDefinition。

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) {
        
        .......... 该部分是处理BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry相关逻辑,跳过, 可以看BeanDefinitionRegistryPostProcessor的解析
		
    
        // Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the bean factory post-processors apply to them!
        // 获取所有实现了BeanFactoryPostProcessor接口的bean name列表,前提是在BeanFactory的BeanDefinitions列表中包含对应的bean定义信息。
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

		// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
        // 存放实现了PriorityOrdered接口的processor
		List priorityOrderedPostProcessors = new ArrayList<>();
        // 存放实现了Ordered接口的processor
		List orderedPostProcessorNames = new ArrayList<>();
        // 存放没有实现排序的processor
		List nonOrderedPostProcessorNames = new ArrayList<>();
        // 遍历前面全量的bean name,将他们归类,放到上面的容器中
		for (String ppName : postProcessorNames) {
            // 如果在第一阶段已经被调用过,就不调用,第一阶段主要是BeanDefinitionRegistryPostProcessor,它继承了BeanFactoryPostProcessor,它会在第一阶段调用。
			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.
        // 首先执行实现了PriorityOrdered接口的processor,对它们进行排序
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
        // 真实执行processor中的逻辑。
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
        // 其次执行实现了Ordered接口的processor,对它们进行排序后执行processor中的逻辑。
		List orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String postProcessorName : orderedPostProcessorNames) {
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		// 最后执行,没有顺序要求的processor
		List 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();
	}

//调用processors中的postProcessBeanFactory方法
private static void invokeBeanFactoryPostProcessors(
			Collection postProcessors, ConfigurableListableBeanFactory beanFactory) {

		for (BeanFactoryPostProcessor postProcessor : postProcessors) {
			StartupStep postProcessBeanFactory = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process")
					.tag("postProcessor", postProcessor::toString);
			postProcessor.postProcessBeanFactory(beanFactory);
			postProcessBeanFactory.end();
		}
	}
复制代码

小结

整个执行流程的源码还是比较清晰并且简单的。重点提下下面两个点:

  1. 我们自定义的BeanFactoryProcessor需要加上 @Component 等注解,为什么?

看源码得知, String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); 获取所有实现了BeanFactoryPostProcessor的Bean Name, 前提所有的Bean都要被注册到 BeanDefinitionRegistry , 通过添加 @Component , @Service 等注解,可以将对应的Bean定义信息注册到BeanFactory中,方便后面实例化Bean。 那么它是在什么地方注册的呢?可以看下 ConfigurationClassPostProcessor 类,它实现了 BeanDefinitionRegistryPostProcessor ,会扫描所有 @Component , @Service 等注解,将对应的Bean Definition注册到BeanFactory中。

  1. 执行顺序问题

我们可以通过实现 PriorityOrdered , Ordered 接口,控制 BeanFactoryProcessor 的执行顺序,, 优先执行实现了 PriorityOrdered 接口,其次是 Ordered ,最后是没有实现任何排序接口的processor。

内置的BeanFactoryPostProcessor

Spring内置了一个比较重要的 BeanFactoryPostProcessor 是 PlaceholderConfigurerSupport , 实现从配置文件中获取属性。

+Spring Boot

你可能感兴趣的:(编程,程序员,Java,java,spring,mvc)