当前位置: 首页 > news >正文

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*/@Overridedefault 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 NameString[] 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 applicableconfigCandidates.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 contextSingletonBeanRegistry 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 contentif (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 classesif (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 necessarythis.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();}}.....
http://www.gsyq.cn/news/57504.html

相关文章:

  • 详细介绍:第七篇:匹配篇 | 怎么像做产品一样,为每个岗位“定制”你的简历?
  • hbuilder是否支持云端部署
  • 2025教育AI供应商TOP10权威评测:AI时代下的技术赋能与行业变革
  • 实用指南:零基础从头教学Linux(Day 54)
  • 完整教程:医疗领域DICOM特征提取工具类综合对比(2025.10更新版)
  • CS2撤回功能与市场经济的结合
  • 面向模块的综合技术之控制集优化(七) - 教程
  • 2025酱酒选品怕踩坑?宴请自饮高性价比核心产区品牌实测
  • 2025年冷却塔工厂权威推荐榜单:横流式冷却塔/节能冷却塔/蒸发式冷却塔设备源头厂家精选
  • 分布式存储数据结构LSM在HBase中的应用
  • 完整教程:FPGA DDR3实战(七):Xilinx FPGA DDR3性能深度测试----吞吐率与延迟精准分析
  • 11.17-11.22 总结
  • 2025年陶瓷防静电地板工厂权威推荐榜单:木基防静电地板/铝合金防静电地板/硫酸钙防静电地板源头厂家精选
  • 2025年钢丝绳牵引格栅机批发厂家权威推荐榜单:抓斗清污机/耙斗清污机/移动抓斗清污机源头厂家精选
  • 2025云南曲靖市玉溪市一对一家教辅导测评排行榜:权威推荐高性价比选择
  • P10683 [COTS 2024] 划分 Particija
  • 纵观当代现状,70年代出生的人,可能别具一格
  • 2025年重庆废气收集处理机构权威推荐榜单:废气处理/废气治理/废气处理设备源头机构精选
  • 征程 6E/M 计算平台部署指南
  • 详细介绍:第三章 FreeRTOS 任务相关 API 函数
  • 2025年口碑好的江苏婚纱照/婚前影像/小众婚纱照/园林婚纱照/光影婚纱照/外景婚纱照/秀禾婚纱照/中式婚纱照/结婚照品牌推荐:弥素摄影领跑
  • 2025年11月22日
  • 【Java后端进行ai coding实践系列】如何使用ai coding达成计划任务增删改查
  • 2025-11-21 hetao1733837的刷题记录
  • C# Avalonia 18- ControlTemplates - FlipPanelTest
  • CTF逆向Re:零基础系统性入门教程-5-动态调试
  • CF1817B Fish Graph
  • 淮安市一对一辅导机构权威排行榜推荐:2026家教机构穿透式测评!
  • 南昌航空大学-软件学院-23207201-吕玉英
  • 从超时到秒杀:三路快排解决数组排序的完整实战与反思