Spring BeanFactoryPostProcessor:机制解读与代码实践

发布于:2025-05-12 ⋅ 阅读:(18) ⋅ 点赞:(0)


在这里插入图片描述

一、BeanFactoryPostProcessor 基本知识总结

1.1 核心定义与作用

BeanFactoryPostProcessor是Spring框架中的一个关键扩展点(位于org.springframework.beans.factory.config包),其核心功能是在Bean实例化之前修改Bean的配置元数据(即BeanDefinition)。通过该接口,开发者可以在容器启动时动态调整Bean属性(如作用域、懒加载、属性值)、注册新的Bean定义,甚至替换现有Bean的实现类

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;

}

1.2 执行时机

  • 在Spring容器加载完所有Bean定义后,Bean实例化之前(即BeanDefinition解析完成但未实例化时)触发
  • 其子接口BeanDefinitionRegistryPostProcessor的执行时机更早,允许在Bean定义注册前进行扩展

1.3 与BeanPostProcessor的区别

对比维度 BeanFactoryPostProcessor BeanPostProcessor
操作对象 BeanDefinition(Bean配置元数据) Bean实例(已初始化对象)
执行时机 容器启动时,Bean实例化前 Bean实例化及初始化前后
典型应用 修改Bean属性、注册BeanDefinition 代理Bean、AOP增强、属性注入后处理

二、BeanFactoryPostProcessor 使用姿势

2.1 修改现有 Bean 的定义

场景:动态修改Bean的作用域(如scope)、懒加载策略(lazy-init)、属性值等。
代码示例

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService");
        // 修改作用域为单例
        beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);  
        // 修改属性值
        MutablePropertyValues pv = beanDefinition.getPropertyValues();
        pv.addPropertyValue("desc", "Modified by BeanFactoryPostProcessor");
    }
}

关键类

  • BeanDefinition:存储Bean的配置元数据,如属性、作用域等。
  • MutablePropertyValues:提供对Bean属性值的动态修改能力 。

2.2 注册新 Bean 定义

场景:动态注册新的Bean到容器中(如基于条件动态生成Bean)。
代码示例

@Component
public class DynamicBeanRegistrar implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        GenericBeanDefinition newDefinition = new GenericBeanDefinition();
        newDefinition.setBeanClass(NewService.class);
        registry.registerBeanDefinition("newService", newDefinition);
    }
}

关键点

  • 使用BeanDefinitionRegistryPostProcessor(BeanFactoryPostProcessor 的子接口)扩展注册能力

2.3 全局配置处理

场景:统一处理所有Bean的配置(如全局设置默认值)。
代码示例

@Component
public class GlobalConfigProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        Arrays.stream(beanFactory.getBeanDefinitionNames())
            .filter(name -> beanFactory.getBeanDefinition(name).getBeanClassName().contains("Controller"))
            .forEach(name -> {
                BeanDefinition definition = beanFactory.getBeanDefinition(name);
                definition.setLazyInit(true);  // 所有Controller类设为懒加载
            });
    }
}

三、BeanFactoryPostProcessor 源码解析

3.1 接口源码

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;

}

子接口扩展

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean definition registry after its
	 * standard initialization. All regular bean definitions will have been loaded,
	 * but no beans will have been instantiated yet. This allows for adding further
	 * bean definitions before the next post-processing phase kicks in.
	 * @param registry the bean definition registry used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

}

BeanDefinitionRegistryPostProcessor 与 BeanFactoryPostProcessor关系

  • 继承关系BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor的子接口。这意味着BeanDefinitionRegistryPostProcessor不仅拥有父接口的功能,还增加了新的能力。
  • 执行顺序:在 Spring 容器启动的过程中,会先执行BeanDefinitionRegistryPostProcessor,之后才会执行BeanFactoryPostProcessor。(稍后会有源码解析)

主要差异

对比维度 BeanDefinitionRegistryPostProcessor BeanFactoryPostProcessor
核心作用 能够对BeanDefinitionRegistry进行操作,比如动态注册、修改或者删除BeanDefinition 主要用于对ConfigurableListableBeanFactory进行修改,像调整 bean 的属性值。
关键方法 postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
执行时机 在所有标准BeanDefinition加载完成之后,但在BeanFactoryPostProcessor执行之前执行。 在所有BeanDefinition都已经注册完成,但还没有实例化任何 bean 之前执行。
典型应用场景 实现动态注册 bean,例如 MyBatis 的MapperScannerConfigurer;自定义注解扫描。 修改 bean 的定义属性,比如PropertySourcesPlaceholderConfigurer

3.2 执行原理 - 源码分析

核心入口AbstractApplicationContext.refresh() 中的 invokeBeanFactoryPostProcessors(beanFactory) 方法。以下是关键逻辑的源码解析:

1. 源码逻辑概览

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// Prepare this context for refreshing.
		prepareRefresh();

		// Tell the subclass to refresh the internal bean factory.
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// Prepare the bean factory for use in this context.
		prepareBeanFactory(beanFactory);

		try {
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);

			// 【本次主角】调用在上下文中注册的BeanFactoryPostProcessor
			invokeBeanFactoryPostProcessors(beanFactory);

			// Register bean processors that intercept bean creation.
			registerBeanPostProcessors(beanFactory);

			// Initialize message source for this context.
			initMessageSource();
/**
 * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
 * respecting explicit order if given.
 * <p>Must be called before singleton instantiation.
 */
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
	// 。。。
}

2. 核心处理逻辑(源码注释版)

public static void invokeBeanFactoryPostProcessors(
		ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
	// 【 1. 处理所有 BeanDefinitionRegistryPostProcessor(子接口)】
	if (beanFactory instanceof BeanDefinitionRegistry) {
		BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
		List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();
		List<BeanDefinitionRegistryPostProcessor> registryPostProcessors =
				new LinkedList<BeanDefinitionRegistryPostProcessor>();
	
		// 分阶段处理:PriorityOrdered → Ordered → 普通实现
	
		// 执行 PriorityOrdered 
		invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);
	
		// 执行 Ordered
		invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors, registry);
	
		// 执行 普通实现
		invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
	}
	
	else {
		// Invoke factory processors registered with the context instance.
		invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
	}
	
	// 。。。
	
	// 【 2. 处理所有 BeanFactoryPostProcessor】
	// 分阶段处理:PriorityOrdered → Ordered → 普通实现
	List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
	List<String> orderedPostProcessorNames = new ArrayList<String>();
	List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
	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);
		}
	}
	
	// 执行 PriorityOrdered 
	invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
	
	// 执行 Ordered
	invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
	
	// 执行 普通实现
	invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
	// 。。。
}

具体执行方法:invokeBeanFactoryPostProcessors

/**
 * Invoke the given BeanFactoryPostProcessor beans.
 */
private static void invokeBeanFactoryPostProcessors(
		Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {

	for (BeanFactoryPostProcessor postProcessor : postProcessors) {
	    // 执行具体的postProcessBeanFactory方法
		postProcessor.postProcessBeanFactory(beanFactory);
	}
}

四、框架级应用案例与源码解析

4.1 ConfigurationClassPostProcessor 实现原理与源码解析

ConfigurationClassPostProcessorBeanDefinitionRegistryPostProcessor 的子类,负责解析 @Configuration 类及其注解(如 @ComponentScan@Bean),动态注册新的 BeanDefinition

核心功能

  1. 扫描配置类: 识别 @Configuration 类,解析其上的 @ComponentScan、@Import 等注解
  2. 处理条件注解: 根据 @Conditional 注解判断是否注册对应的 BeanDefinition
  3. 生成代理类: 通过 CGLIB 代理 @Configuration 类,确保 @Bean 方法返回单例对象

源码解析

入口方法

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        // 1. 幂等性检查(避免重复处理)
        int registryId = System.identityHashCode(registry);
        if (registriesPostProcessed.contains(registryId)) {
            throw new IllegalStateException("重复处理配置类");
        }
        registriesPostProcessed.add(registryId);
        
        // 2. 处理配置类
        processConfigBeanDefinitions(registry);
    }
}  

核心方法 processConfigBeanDefinitions

protected void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	// 。。。
    // 1. 获取所有候选配置类(标记了@Configuration的Bean)
	// Parse each @Configuration class
	ConfigurationClassParser parser = new ConfigurationClassParser(
			this.metadataReaderFactory, this.problemReporter, this.environment,
			this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    // 。。。
    // 2. 解析配置类
    parser.parse(candidates);  // 解析@ComponentScan、@Import、@Bean等注解
    
    // 。。。
    // 3. 注册新的BeanDefinition
    this.reader.loadBeanDefinitions(configClasses);  // 将解析结果注册到容器
}  

4.2 PropertySourcesPlaceholderConfigurer 实现原理与源码解析

PropertySourcesPlaceholderConfigurer 是 Spring 中用于解析属性占位符(如 ${jdbc.url})的 BeanFactoryPostProcessor 实现类。其核心功能是在 Bean 实例化前,将配置文件中的占位符替换为实际值

工作流程

  1. 加载属性源: 从环境变量、@PropertySource 注解指定的文件、系统属性等来源收集键值对,合并到 MutablePropertySources
  2. 递归解析占位符: 遍历所有 BeanDefinition,通过 BeanDefinitionVisitor 替换 ${...} 占位符为实际值,支持嵌套占位符(如 ${outer.${inner.key}}

源码解析

入口方法

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
	// 。。。

	processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources));
	// 。。。
}
/**
 * Visit each bean definition in the given bean factory and attempt to replace ${...} property
 * placeholders with values from the given properties.
 */
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
		final ConfigurablePropertyResolver propertyResolver) throws BeansException {

	// "${"
	propertyResolver.setPlaceholderPrefix(this.placeholderPrefix);	
	// "}"
	propertyResolver.setPlaceholderSuffix(this.placeholderSuffix);
	// ":"
	propertyResolver.setValueSeparator(this.valueSeparator);

	// 。。。
	// 执行具体解析逻辑
	doProcessProperties(beanFactoryToProcess, valueResolver);
}
protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
		StringValueResolver valueResolver) {

	// 。。。

	// 具体解析逻辑
	beanFactoryToProcess.resolveAliases(valueResolver);

	// 具体解析逻辑
	beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);
}

五、高频面试题与解析

5.1 什么是 BeanFactoryPostProcessor?它的作用是什么?

BeanFactoryPostProcessor 是 Spring 容器初始化过程中的一个扩展点,允许开发者在 Bean 定义加载完成后、Bean 实例化之前修改 BeanDefinition。其核心方法是:

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

典型应用

  • 修改 BeanDefinition 的属性值(如替换占位符)
  • 注册额外的 BeanDefinition
  • 调整 Bean 的作用域或懒加载特性

5.2 BeanFactoryPostProcessor与BeanPostProcessor的区别?

  • BeanFactoryPostProcessor:操作BeanDefinition,在Bean实例化前执行
  • BeanPostProcessor:操作Bean实例,在Bean初始化前后执行(如@PostConstructAOP代理)

5.3 如何自定义一个 BeanFactoryPostProcessor?请举例说明。

自定义步骤:

  • 实现BeanFactoryPostProcessor接口,重写postProcessBeanFactory方法。
  • 在方法中通过beanFactory.getBeanDefinition("beanName")获取并修改 BeanDefinition
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition bd = beanFactory.getBeanDefinition("myBean");
        bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); // 修改作用域为原型
        bd.getPropertyValues().add("age", 18); // 添加属性值
    }
}

5.4 BeanFactoryPostProcessor的执行顺序如何控制?

  • 实现Ordered接口:重写getOrder()方法返回优先级值(越小越优先)。
  • 使用@Order注解:指定优先级值

5.5 为什么 PropertySourcesPlaceholderConfigurer 是 BeanFactoryPostProcessor 的典型实现?

PropertySourcesPlaceholderConfigurer用于解析配置文件中的占位符,如${db.url}。它在 Bean 实例化前,读取配置源,将BeanDefinition中的占位符替换为实际值,本质是修改BeanDefinition的属性值,所以是BeanFactoryPostProcessor的典型应用。


网站公告

今日签到

点亮在社区的每一天
去签到