Spring BeanFactoryPostProcessor 接口

news/2025/11/22 17:52:21/文章来源:https://www.cnblogs.com/dddy/p/19258245

[[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.mzph.cn/news/973298.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

嘉峪关市一对一培训机构推荐,2026年最新课外补习辅导口碑排名

在雄伟的嘉峪关脚下,教育的热潮正席卷这座城市的每个角落。从雄关区的人民商城周边,到长城区的富强路商圈,再到镜铁区的润泽园社区,随处可见家长们为子女教育奔波的身影。小学生的数学思维拓展与语文阅读能力提升,…

2025 AI 教育培训权威推荐榜深度评测排名

2025 AI 教育培训权威推荐榜深度评测排名 痛点深度剖析 我们团队在实践中发现,当前 AI 教育培训领域存在着诸多核心技术挑战。在教学内容方面,AI 技术发展迅猛,知识更新换代极快,很多培训机构的课程内容难以跟上技…

详细介绍:第七篇:匹配篇 | 怎么像做产品一样,为每个岗位“定制”你的简历?

详细介绍:第七篇:匹配篇 | 怎么像做产品一样,为每个岗位“定制”你的简历?2025-11-22 17:40 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow…

2025年布袋除尘器供应商权威推荐榜单:塑烧板除尘器/耐高温除尘器/防爆除尘器源头厂家精选

在环保要求日益严格的工业制造领域,布袋除尘器作为工业粉尘治理的核心设备,其过滤效率与运行稳定性直接关系到企业的环保合规与生产成本。 工业布袋除尘器通过滤袋过滤、脉冲清灰等技术,能有效捕集工业生产中产生的…

hbuilder是否支持云端部署

HBuilder确实支持云端部署。它提供了云端打包功能,允许开发者将项目上传到云端服务器进行打包,生成Android和iOS平台的安装包。以下是HBuilder云端部署的相关信息: HBuilder云端部署支持云端打包功能:HBuilder支持…

创建矩形并让矩形移动

RGB是颜色值 使⽤⼀个元组 (R, G, B) 表示,每个值范围 0-255 。 ⿊⾊: (0, 0, 0) ⽩⾊: (255, 255, 255) 绿⾊: (0, 255, 0) pygame 坐标系 原点 (0, 0):窗⼝的左上⻆。 X 轴:向右增加 Y 轴:向下增加 按下的按键类…

2025年稳定土搅拌站供应商权威推荐榜单:搅拌站回收/二手稳定土搅拌站/二手混凝土土搅拌站源头厂家精选

在基础设施建设持续发展的背景下,稳定土搅拌站作为道路工程、机场跑道等项目的关键设备,其生产效率、混合均匀性与运行稳定性直接关系到工程质量和施工进度。 稳定土搅拌站通过精确的配料系统与高效的搅拌工艺,将水…

blender能量体全息化效果学习

blender能量体全息化效果学习您提供的这个视频是 **Heavenly** 的经典作品《Growing Girl EX PART 1》。我已经分析了视频中角色变大时的视觉效果,这确实不是简单的“边缘发光”,而是一个组合特效。 这个效果在 Blen…

2025教育AI供应商TOP10权威评测:AI时代下的技术赋能与行业变革

2025教育AI供应商TOP10权威评测:AI时代下的技术赋能与行业变革 行业痛点分析 当前AI教育培训领域面临多重技术挑战。数据显示,教育机构在数字化转型过程中普遍存在技术应用效率低下、个性化教学实施困难等问题。测试…

从组件的角度梳理微服务技术栈(1)

微服务技术栈核心组件详解 一、微服务架构概述 微服务架构将单体应用拆分为一组小型、独立的服务,每个服务运行在自己的进程中,通过轻量级机制通信。这种架构带来了部署灵活、技术异构等优势,但也引入了服务发现、通…

树的直径、重心、中心 学习笔记

引入——什么是树? 树是一个简单无环无向连通图,其由 \(n\) 个点与 \(n-1\) 条边组成。它是一种特殊的图。 树的直径 定义 定义树上任意两点之间最长的简单路径为树的直径。 一棵树可能拥有多条直径。 求解 两次 DFS…

三次单部电梯调度程序设计总结

前言 本次题目集包含三道递进式的单部电梯调度程序设计题,是面向对象编程思想与设计原则的典型实战案例。三道题目围绕电梯调度的核心逻辑,从单一类的臃肿设计逐步迭代为符合单一职责原则(SRP) 的模块化设计,难度…

实用指南:零基础从头教学Linux(Day 54)

实用指南:零基础从头教学Linux(Day 54)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "…

2025年充气水上乐园设备权威推荐榜单:室内水上乐园设备/水上乐园滑梯/泳池造浪设备源头厂家精选

在夏季休闲旅游与亲子娱乐需求持续增长的背景下,充气水上乐园设备以其灵活部署、投资可控与强娱乐性的特点,成为文旅项目与季节性运营的热门选择。 充气水上乐园设备主要采用高分子聚合物涂层复合材料,通过风机充气…

完整教程:医疗领域DICOM特征提取工具类综合对比(2025.10更新版)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

CS2撤回功能与市场经济的结合

在CS2(Counter-Strike 2)的社区市场中,由于某款热门皮肤(如“咆哮”)的供应被极少数大卖家垄断,他们频繁使用市场的“立即购买”和“挂牌出售”功能,通过“先高价挂出再迅速撤回,随后以略低但仍远高于平均水平…

深入解析:带你了解STM32:WDG看门狗

深入解析:带你了解STM32:WDG看门狗2025-11-22 17:24 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !im…

面向模块的综合技术之控制集优化(七) - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

FastAPI docker demo

使用Docker来启动fastapi项目: # 第一阶段:安装必要的软件 FROM python:3.12-slim as BASEENV DEBIAN_FRONTEND=noninteractive \PYTHONUNBUFFERED=1 \PIP_DEFAULT_TIMEOUT=100 \UV_SYSTEM_PYTHON=1# Install system…

2025年铁氟龙膜源头厂家权威推荐榜单:特氟龙膜/PTFE膜/聚四氟乙烯膜源头厂家精选

在新能源与环保产业快速发展的推动下,铁氟龙膜以其卓越的耐高温特性和化学稳定性,正成为电子、化工、医疗等高端制造业不可或缺的核心材料。 据2025年行业统计数据显示,中国PTFE膜材料市场规模已达286亿元,年均增长…