Spring BeanFactoryPostProcessor 接口

[[Spring IOC 源码学习总笔记]]

BeanFactoryPostProcessor是 Spring 框架提供的一个扩展点接口,它允许开发者在 Spring 在BeanFactory 加载了所有bean定义,但尚未实例化任何bean 之后,对底层的 BeanDefinition 和 BeanFactory 进行扩展定制, 包括修改已注册的bean定义 添加新的bean定义等等。

BeanFactoryPostProcessor的主要作用包括:

  1. 修改已注册的Bean定义: 可以通过BeanFactoryPostProcessor来修改已注册的bean的配置信息,例如修改属性值、添加新的属性等。
  2. 添加新的Bean定义: 可以向容器中添加新的bean定义,这样在实例化bean时,新定义的bean也会被纳入管理。
  3. 对Bean定义进行后处理: 可以在容器加载了bean的定义后对这些定义进行后处理,以满足特定的需求。

BeanFactoryPostProcessor

org.springframework.beans.factory.config.BeanFactoryPostProcessor 的源码

package org.springframework.beans.factory.config;

import org.springframework.beans.BeansException;

/**
 * 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.
 *

 *
 * <p>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.
 *
 * <p>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.
 *
 * <h3>Registration</h3>
 * <p>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}.
 *
 * <h3>Ordering</h3>
 * <p>{@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.
	 * 在加载了所有bean定义,但尚未实例化任何bean。(可以对底层的 BeanDefinition 和 BeanFactory 进行扩展定制)
	 *
	 * @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;

}

相关源码

org.springframework.context.support.AbstractApplicationContext#refresh 部分源码

@Override
public void refresh() throws BeansException, IllegalStateException {
	// 容器刷新, 执行时, 需要锁住
	synchronized (this.startupShutdownMonitor) {
		StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

		// Prepare this context for refreshing.
		/**
		 * 一, (ApplicationContex)预准备工作;
		 */
		prepareRefresh();

		// Tell the subclass to refresh the internal bean factory.
		/**
		 * 二, 获取一个新的 BeanFactory;
		 */
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		/**
		 * 三,(BeanFactory)预准备工作;
		 */
		// Prepare the bean factory for use in this context.
		prepareBeanFactory(beanFactory);

		try {
			// Allows post-processing of the bean factory in context subclasses.
			/**
			 * 四, beanFactory 已经准备好了, 给子类(Context)预留一个扩展点; (这里是空实现)
			 */
			postProcessBeanFactory(beanFactory);

			StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");

			// Invoke factory processors registered as beans in the context.
			/**
			 * 五, 调用 BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor;
			 * 还要注意一点 BeanDefinitionRegistryPostProcessor 是继承自 BeanFactoryPostProcessor的
			 *
			 * 总的来说, 调用的优先级是
			 * 1. 调用接口的优先级:
			 *    1. 优先调用(子类) BeanDefinitionRegistryPostProcessor
			 *    2. 再调用(父类) BeanFactoryPostProcessor
			 * 2. 调用添加的方式的优先级:
			 *    1. 优先调用外部入参, 即直接通过{@link AbstractApplicationContext#addBeanFactoryPostProcessor(org.springframework.beans.factory.config.BeanFactoryPostProcessor)} 代码添加的
			 *    2. 再调用容器中实现 BeanFactoryPostProcessor 或者 BeanDefinitionRegistryPostProcessor 的 Bean
			 * 见: {@link org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List)}
			 *
			 * 比如:
			 * {@link org.springframework.context.support.PropertySourcesPlaceholderConfigurer} 处理 SPEL 表达式的
			 */
			invokeBeanFactoryPostProcessors(beanFactory);

	....

BeanDefinitionRegistryPostProcessor 接口

BeanDefinitionRegistryPostProcessor(BDRPP) 接口继承自BeanFactoryPostProcessor(BFPP) 它会优先于BFPP调用, 目的是可以在BFPP之前 注册/修改 BeanDefinition 到 BeanFactory

org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor

package org.springframework.beans.factory.support;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

/**
 * Extension to the standard {@link BeanFactoryPostProcessor} SPI, allowing for
 * the registration of further bean definitions <i>before</i> regular
 * BeanFactoryPostProcessor detection kicks in. In particular,
 * BeanDefinitionRegistryPostProcessor may register further bean definitions
 * which in turn define BeanFactoryPostProcessor instances.
 *
 * 对标准 {@link BeanFactoryPostProcessor} SPI的扩展,允许在常规 BeanFactoryPostProcessor检测开始之前注册更多的bean定义。
 *  特别是,BeanDefinitionRegistryPostProcessor 可以注册进一步的bean定义,这些bean定义又定义了 BeanFactoryPostProcessor 实例。
 *
 * @author Juergen Hoeller
 * @since 3.0.1
 * @see org.springframework.context.annotation.ConfigurationClassPostProcessor
 */
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;

	/**
	 * Empty implementation of {@link BeanFactoryPostProcessor#postProcessBeanFactory}
	 * since custom {@code BeanDefinitionRegistryPostProcessor} implementations will
	 * typically only provide a {@link #postProcessBeanDefinitionRegistry} method.
	 * @since 6.1
	 */
	@Override
	default void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
	}

}

Srping 对于注解的支持实现

一个例子是在 Spring 中 对于注解的支持就是通过 BeanDefinitionRegistryPostProcessor的扩展实现的, 见关系图

Pasted image 20251122144411

注意: 关于 Spring IOC 支持注解最原始的入口点 并不在这.
本文只讨论 Spring 是如何通过 BeanDefinitionRegistryPostProcessor 扩展实现对注解的支持

org.springframework.context.annotation.ConfigurationClassPostProcessor 部分源码


/**
 * 主要负责解析注解的关键类, 注意它实现的其中一个接口: BeanDefinitionRegistryPostProcessor
 *
 * {@link BeanFactoryPostProcessor} used for bootstrapping processing of
 * {@link Configuration @Configuration} classes.
 * <p>Registered by default when using {@code <context:annotation-config/>} or
 * {@code <context:component-scan/>}. Otherwise, may be declared manually as
 * with any other {@link BeanFactoryPostProcessor}.
 *
 * <p>This post processor is priority-ordered as it is important that any
 * {@link Bean @Bean} methods declared in {@code @Configuration} classes have
 * their corresponding bean definitions registered before any other
 * {@code BeanFactoryPostProcessor} executes.
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @author Phillip Webb
 * @author Sam Brannen
 * @since 3.0
 */
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
		BeanRegistrationAotProcessor, BeanFactoryInitializationAotProcessor, PriorityOrdered,
		ResourceLoaderAware, ApplicationStartupAware, BeanClassLoaderAware, EnvironmentAware {
	public ConfigurationClassPostProcessor(){
		System.out.println("ConfigurationClassPostProcessor 构造");
	}
	
	....
	/**
	 * Build and validate a configuration model based on the registry of
	 * {@link Configuration} classes.
	 */
	public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		/**
		 * 存所有视为 Candidate 的 BeanDefinition
		 */
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		//拿到所有的已注册的 Bean Name
		String[] candidateNames = registry.getBeanDefinitionNames();

		// 遍历, 筛选视为 Candidate 的 beanDefinition, 把它们添加到 configCandidates 中
		for (String beanName : candidateNames) {
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			/**
			 * BeanDefinition 如果包含 configurationClass 属性, 则表示该 beanDefinition 已经被处理过了
			 */
			if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
				if (logger.isDebugEnabled()) {
					logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
				}
			}
			/**
			 * 如果是该 (bean)beanDefinition
			 *  1. 添加了 @Configuration 会被视作是 Candidate 放入 configCandidates
			 *  2. 如果添加了 @Component, @ComponentScan @Import ,@ImportResource 或者 有方法是添加了 @Bean 注解的, 也会被视作是 Candidate 放入 configCandidates
			 *  并且给它设置属性 configurationClass 值为 'lite' 区分一下
			 *
			 * <!> 所以能被 Spring 识别为bean 添加到容器中的注解, 就是以上的2种情况.
			 */
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

		// Return immediately if no @Configuration classes were found
		// 如果没有任何 Candidate , 返回
		if (configCandidates.isEmpty()) {
			return;
		}
		// 排序 即: @Order
		// Sort by previously determined @Order value, if applicable
		configCandidates.sort((bd1, bd2) -> {
			int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
			int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
			return Integer.compare(i1, i2);
		});

		/**
		 * 这一块是对 bean的 自定义命名生成 策略的处理
		 */
		// Detect any custom bean name generation strategy supplied through the enclosing application context
		SingletonBeanRegistry sbr = null;
		if (registry instanceof SingletonBeanRegistry _sbr) {
			sbr = _sbr;
			if (!this.localBeanNameGeneratorSet) {
				BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
						AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);//这个是默认的 名称生成器
				if (generator != null) {
					this.componentScanBeanNameGenerator = generator;
					this.importBeanNameGenerator = generator;
				}
			}
		}
		// 环境对象
		if (this.environment == null) {
			this.environment = new StandardEnvironment();
		}

		// Parse each @Configuration class
		/**
		 * ConfigurationClassParser: 解析注解的关键解析对象
		 * 又开始倒手了.
		 */
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);

		// 用 set 方便去重 集合运算吧
		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		// 已经解析处理过的
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		do {
			StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
			/**
			 * <!> 重点,  用 ConfigurationClassParser 去解析
			 * 最终得到的是 Set<ConfigurationClass> !
			 */
			parser.parse(candidates);
			parser.validate();

			Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
			// 移出 已经解析处理过的
			configClasses.removeAll(alreadyParsed);

			/**
			 * <!> 重点, 解析得到 Set<ConfigurationClass> 再用 ConfigurationClassBeanDefinitionReader 去加载 BeanDefinition
			 */
			// Read the model and create bean definitions based on its content
			if (this.reader == null) {
				this.reader = new ConfigurationClassBeanDefinitionReader(
						registry, this.sourceExtractor, this.resourceLoader, this.environment,
						this.importBeanNameGenerator, parser.getImportRegistry());
			}
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);
			processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();

			candidates.clear();
			if (registry.getBeanDefinitionCount() > candidateNames.length) {
				String[] newCandidateNames = registry.getBeanDefinitionNames();
				Set<String> oldCandidateNames = Set.of(candidateNames);
				Set<String> alreadyParsedClasses = new HashSet<>();
				for (ConfigurationClass configurationClass : alreadyParsed) {
					alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
				}
				for (String candidateName : newCandidateNames) {
					if (!oldCandidateNames.contains(candidateName)) {
						BeanDefinition bd = registry.getBeanDefinition(candidateName);
						if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
								!alreadyParsedClasses.contains(bd.getBeanClassName())) {
							candidates.add(new BeanDefinitionHolder(bd, candidateName));
						}
					}
				}
				candidateNames = newCandidateNames;
			}
		}
		while (!candidates.isEmpty());

		// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
		if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
			sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
		}

		// Store the PropertySourceDescriptors to contribute them Ahead-of-time if necessary
		this.propertySourceDescriptors = parser.getPropertySourceDescriptors();

		if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory cachingMetadataReaderFactory) {
			// Clear cache in externally provided MetadataReaderFactory; this is a no-op
			// for a shared cache since it'll be cleared by the ApplicationContext.
			cachingMetadataReaderFactory.clearCache();
		}
	}
	.....
posted @ 2025-11-22 17:50  daidaidaiyu  阅读(8)  评论(0)    收藏  举报