流程图解Spring Framework(五) Spring BeanFactoryPostProcessor如何工作的?

本文主要是介绍流程图解Spring Framework(五) Spring BeanFactoryPostProcessor如何工作的?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

BeanPostProcessor这个概念可以认为是在spring声明周期中留下的一个钩子,这个钩子是在所有的BeanDefinition被扫描完成之后这个阶段的。我们可以在这里做很多事情,Spring框架里面很多特性也利用了这里,比如属性注入

具体在 查看详细信息

BeanFactoryPostProcessor的定义

在Spring框架设计之中,我们可以看到优秀的设计之处,最为精妙的就是扩展点的设置,这样使我们对Spring的扩展,很多时候只需要继承一个类,把它注册为一个Bean即可。

BeanFactoryPostProcessor从字面的意思上是BeanFactory的后置处理器。也可以认为是在spring生命周期中留下的一个钩子,这个钩子是在所有的BeanDefinition被扫描完成之后这个阶段的。但是在Spring中是这样描述这个扩展点的作用的,

Allows for custom modification of an application context’s bean definitions,
adapting the bean property values of the context’s underlying bean factory`

翻译过来大致是下面个意思

这个扩展点允许修改应用程序上下文(ApplicationContext)中的BeanDefinition,以及bean的属性值。

BeanFactoryPostProcessor 的执行优先级

因为BeanFactoryPostProcessor是一个扩展点,所以当有多个Bean实现这个扩展点的时候,必回存在一个执行顺序的问题,那么Spring是如何设计的呢?

`

1.执行BeanDefinitionRegistryPostProcessor接口的后置处理器

  • 执行通过配置的BeanDefinitionRegistry后置处理器,执行顺序是PriorityOrdered(排序是按照从小到大排)-> Ordered -> 普通的

  • 执行硬编码的BeanDefinitionRegistryPostProcessor

2.执行普通的BeanFactoryPostProcessor

  • 执行硬编码的后置处理器

  • 执行通过配置注册的处理器,执行顺序是PriorityOrdered(排序是按照从小到大排)->Ordered->普通的

在这一节可以看到后置处理器的执行顺序,应该大家都有一个疑惑,这么优秀的东西是如何实现的呢?
不仅大胆的想想,无非就是会把所有的实现这个扩展点的Bean都找出来,然后排序,最后执行,那么Spring是不是这样做的呢?

BeanFactoryPostProcessor的源码阅读

接口定义

在Spring框架中的接口定义如下

public interface BeanFactoryPostProcessor {// 上下文中的BeanFactoryvoid postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;}

执行逻辑

Spring容器的启动入口

AbstractApplicationContext#refresh 的第三步invokeBeanFactoryPostProcessors

public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {prepareRefresh();ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();prepareBeanFactory(beanFactory);try {postProcessBeanFactory(beanFactory);// 执行上下文中注册的Bean工厂后置处理器invokeBeanFactoryPostProcessors(beanFactory);...}}
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {//// 1. 首先执行 BeanDefinitionRegistryPostProcessors (优秀的BeanFactoryPostProcessor)//Set<String> processedBeans = new HashSet<String>();// 1.0 如果beanFactory是BeanDefinitionRegistry类型的,也就是说BeanFactory中允许对BeanDefinition进行增删改的操作if (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;// 1.1 先执行硬编码的BeanDefinitionRegistryPostProcessorList<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();List<BeanDefinitionRegistryPostProcessor> registryPostProcessors =new LinkedList<BeanDefinitionRegistryPostProcessor>();for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {BeanDefinitionRegistryPostProcessor registryPostProcessor =(BeanDefinitionRegistryPostProcessor) postProcessor;registryPostProcessor.postProcessBeanDefinitionRegistry(registry);registryPostProcessors.add(registryPostProcessor);}else {regularPostProcessors.add(postProcessor);}}String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);// 1.2 首先执行实现PriorityOrdered接口的BeanDefinitionRegistryPostProcessorList<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(beanFactory, priorityOrderedPostProcessors);registryPostProcessors.addAll(priorityOrderedPostProcessors);invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);// 1.3 接下来执行实现Ordered接口的BeanDefinitionRegistryPostProcessorspostProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);List<BeanDefinitionRegistryPostProcessor> orderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}// 排序sortPostProcessors(beanFactory, orderedPostProcessors);registryPostProcessors.addAll(orderedPostProcessors);invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors, registry);//  1.4 执行其它的硬编码的的BeanDefinitionRegistryPostProcessorsboolean reiterate = true;while (reiterate) {reiterate = false;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName)) {BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);registryPostProcessors.add(pp);processedBeans.add(ppName);pp.postProcessBeanDefinitionRegistry(registry);reiterate = true;}}}// 执行invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);}else {// Invoke factory processors registered with the context instance.invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}//// 2. 执行 BeanFactoryPostProcessor //String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);// 2.1 将后置处理器根据不同类型(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);}}// 2.2 首先执行优先级Order类型的后置处理器sortPostProcessors(beanFactory, priorityOrderedPostProcessors);invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);// 2.3 执行带有Order接口的后置处理器List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();for (String postProcessorName : orderedPostProcessorNames) {orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}sortPostProcessors(beanFactory, orderedPostProcessors);invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);// 2.4 执行其它的所有后置处理器List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();for (String postProcessorName : nonOrderedPostProcessorNames) {nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);// 清空元数据cache,因为beandefine有可能会变beanFactory.clearMetadataCache();}

BeanFactoryPostProcessor 在Spring中的应用

在Spring中,有很多的框架类实现了这个类并且做了一些事情。。
在这里插入图片描述

上图是一个只依赖spring-boot-starter-web的空工程中所有的BeanFactoryPostProcessor实现,可以看到有以下扩展点

  • PropertyResourceConfigurer。配合上PlaceholderResolvingStringValueResolver,为@Value注解提供支持
  • BeanDefinitionRegistryPostProcessor,这个比如Dubbo中的Reference和Service就是通过这个接口在Spring容器中注册为Bean 的,比较适用于一些框架添加自定义的Bean的场景。
  • CustomScopeConfigurer(自定义的Scope处理)
  • ServletComponentRegisteringPostProcessor(自动扫描Servlet的三剑客)
  • DeprecatedBeanWarner(在Bean上面添加一个过期的标志,有意思)
  • AbstractDependsOnBeanFactoryPostProcessor(用于动态声明特定类型的所有bean应该依赖于一个或多个特定bean。,应用场景比如在一些框架上,有一些Bean进行初始化之前必须等待一些连接类Bean准备好,如这里面的MongoClient,MongoClientFactoryBean)
  • CustomAutowireConfigurer,自定义Qualifier类型,和@Qualifier一个意思
  • ConfigurationBeanFactoryMetaData 在bean工厂初始化期间记住Bean定义元数据的一个工具类。保存了工厂方法名称和工厂Bean的名称,可以后续根据beanName

BeanFactoryPostProcessor 小例子

  1. 使用BeanFactoryPostProcessor注册一个bean
@Component
public class RegisteBeanBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor,Ordered {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {RootBeanDefinition rbd = new RootBeanDefinition();rbd.setTargetType(User.class);rbd.setBeanClass(User.class);registry.registerBeanDefinition("user-wuhulala", rbd);}@Overridepublic int getOrder() {return 0;}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {// do nothing}
}
  1. 使用BeanFactoryPostProcessor丰富Bean的属性
public class ModifyBeanBeanFactoryPostProcessor implements BeanFactoryPostProcessor,Ordered {@Overridepublic int getOrder() {return 0;}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {RootBeanDefinition bd = (RootBeanDefinition) beanFactory.getBeanDefinition("user-wuhulala");MutablePropertyValues values = new MutablePropertyValues();values.addPropertyValue("name", "wuhulala");values.addPropertyValue("age", 21);Address address = new Address();address.setName("浙江省");values.addPropertyValue("address", address);bd.setPropertyValues(values);}
}

使用BeanFactoryPostProcessor注意点

  1. 如果使用BeanDefinitionRegistry接口,那么应该是对当前IOC容器的Bean的一种补充或删除。
  2. BeanFactoryPostProcessor可以操作BeanDefinition,但永远不要与bean实例交互。也就是不要在这里进行Bean的实例化。 因为在这里实例化的话会过早,违反了容器的设计规则并有可能会导致意外的副作用。比如这里初始化的Bean依赖于其它的Bean,就会导致这个链路上的Bean都进行了初始化,从而导致它依赖Bean没有被BeanFactoryPostProcessor处理过对应的BeanDefinition。如果需要bean实例交互,可以实现另一个扩展点 BeanPostProcessor。
  3. 在BeanFactoryPostProcessor不要进行Bean的注册。

聊聊设计

Spring扩展点在Spring核心中是很重要的概念,spring本身就内置了很多实现。如果我们需要扩展Spring的功能,他们是很好的方式。并且它们可以像插件一样很好的工作。

在我们日常进行程序的设计编码时候,当一处进行多次的修改(添加、删除、修改细节)的时候,我们也可以尝试着抽取出一个扩展点,这样会使我们的程序变得极为简单。

比如我最近在做的一个项目流程,其实在项目新增之前和之后都需要进行很多的逻辑处理,比如调用远程服务、参数校验、后置处理,并且需求变动很频繁,那么现在依葫芦画瓢,把项目流程分为新增前、新增、新增后三个逻辑,抽象出preAddProcessor/postAddProcessor两个接口,最后用一段通用逻辑进行拼接,如有兴趣,可私聊。

这篇关于流程图解Spring Framework(五) Spring BeanFactoryPostProcessor如何工作的?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1113919

相关文章

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

Java使用ANTLR4对Lua脚本语法校验详解

《Java使用ANTLR4对Lua脚本语法校验详解》ANTLR是一个强大的解析器生成器,用于读取、处理、执行或翻译结构化文本或二进制文件,下面就跟随小编一起看看Java如何使用ANTLR4对Lua脚本... 目录什么是ANTLR?第一个例子ANTLR4 的工作流程Lua脚本语法校验准备一个Lua Gramm

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

Java Optional的使用技巧与最佳实践

《JavaOptional的使用技巧与最佳实践》在Java中,Optional是用于优雅处理null的容器类,其核心目标是显式提醒开发者处理空值场景,避免NullPointerExce... 目录一、Optional 的核心用途二、使用技巧与最佳实践三、常见误区与反模式四、替代方案与扩展五、总结在 Java

基于Java实现回调监听工具类

《基于Java实现回调监听工具类》这篇文章主要为大家详细介绍了如何基于Java实现一个回调监听工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录监听接口类 Listenable实际用法打印结果首先,会用到 函数式接口 Consumer, 通过这个可以解耦回调方法,下面先写一个

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

Java字符串处理全解析(String、StringBuilder与StringBuffer)

《Java字符串处理全解析(String、StringBuilder与StringBuffer)》:本文主要介绍Java字符串处理全解析(String、StringBuilder与StringBu... 目录Java字符串处理全解析:String、StringBuilder与StringBuffer一、St

springboot整合阿里云百炼DeepSeek实现sse流式打印的操作方法

《springboot整合阿里云百炼DeepSeek实现sse流式打印的操作方法》:本文主要介绍springboot整合阿里云百炼DeepSeek实现sse流式打印,本文给大家介绍的非常详细,对大... 目录1.开通阿里云百炼,获取到key2.新建SpringBoot项目3.工具类4.启动类5.测试类6.测

Spring Boot循环依赖原理、解决方案与最佳实践(全解析)

《SpringBoot循环依赖原理、解决方案与最佳实践(全解析)》循环依赖指两个或多个Bean相互直接或间接引用,形成闭环依赖关系,:本文主要介绍SpringBoot循环依赖原理、解决方案与最... 目录一、循环依赖的本质与危害1.1 什么是循环依赖?1.2 核心危害二、Spring的三级缓存机制2.1 三

在Spring Boot中浅尝内存泄漏的实战记录

《在SpringBoot中浅尝内存泄漏的实战记录》本文给大家分享在SpringBoot中浅尝内存泄漏的实战记录,结合实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录使用静态集合持有对象引用,阻止GC回收关键点:可执行代码:验证:1,运行程序(启动时添加JVM参数限制堆大小):2,访问 htt