【小白的Spring源码手册】 BeanFactoryPostProcessor的注册和用法(BFPP)

目录

  • 前言
  • 应用
    • 1. 手动注册
    • 2. 自动注册
    • 3. 优先级


前言

沿用上一篇文章的流程图,我们的注解类应用上下文中的AnnotationConfigApplicationContext#scan(String...)方法已经将所有BeanDefinition注册到了IoC容器中。完成注册后,开始执行AbstractApplicationContext#refresh()方法,这个方法中Spring向外部提供了几个非常重要的扩展点:BeanFactoryPostProcessor、BeanPostProcessor。他们的作用如下:

  • BeanFactoryPostProcessor:简称BFPP,用于管理BeanDefinition,甚至是管理整个IoC容器,常见业务实现有指定限定符(@Qualifier)、占位符替换(@Value)、配置类注册定义(@Configuration)等等;
  • BeanPostProcessor:简称BPP,用于管理Bean生命周期,常见业务实现有初始化(@PostConstruct)、注入依赖(@Autowired)、代理与包装Bean对象注册事件监听器销毁(@PreDestroy)、以及其它生命周期内事件处理等等。

在这里插入图片描述

学习和理解这两类处理器,能让你了解很多业务中常用功能的实现原理,看过之后就会恍然大悟,哦!原来我们日常业务使用的注解原来是这么回事。


是后处理器,还是后置处理器?Post Processor直译过来就是后处理器或者后置处理器的意思,两者意思大致相同,网上两个词也都在用。虽然这些处理器接口也并未声明它属于某些行为的后置处理器;也没有相对应的前置处理器(PreProcessor),但就总体流程和接口中方法的注释来看,BeanFactoryPostProcessor#postProcessBeanFactory就是IoC容器初始化流程的后置处理器,用来处理容器初始化后的事件;BeanPostProcessor#postProcessBeforeInitialization、BeanPostProcessor#postProcessAfterInitialization这两个方法则是Bean生命周期(BeanPostProcessor有很多实现类,用于分别处理各个阶段)中初始化前后的后置处理器,关于Bean生命周期后面会发文专门学习探讨一下。


综合来看,怎么称呼都没问题,不过我会在下文中都用后处理器来称呼。


其它Spring源码文章:
Bean的扫描、装配和注册,面试学习可用
BeanFactory后处理器的注册与执行——BeanFactoryPostProcessor(BFPP)
Bean后处理器的注册与执行——BeanPostProcessor(BPP)





应用

关于BFPP的类型:

BeanFactoryPostProcessor:提供postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)方法,在IoC容器标准初始化完成后,修改IoC容器内容,支持修改Bean定义、允许覆盖或添加属性。
BeanDefinitionRegistryPostProcessor:是BeanFactoryPostProcessor的子类,添加了一个新方法postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry),这个方法则更强调在IoC容器标准初始化完成后,执行postProcessBeanFactory方法之前,注册额外的Bean定义,这些新注册的内容同样会受postProcessBeanFactory方法影响。

1. 手动注册

所有实现BeanFactoryPostProcessor类的BFPP,都可以在上下文容器执行refresh方法前,通过AbstractApplicationContext#addBeanFactoryPostProcessor方法手动注册。

  AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();ctx.addBeanFactoryPostProcessor(new BfppA());ctx.addBeanFactoryPostProcessor(new BfppB());// 手动注册需确保注册必须在执行refresh方法前注册ctx.refresh();

手动注册的方式在Spring Boot启动类中比较常见,很多功能都是通过手动注册BFPP的方式来实现的。对Spring Boot感兴趣的,可以去看看SpringBoot的启动类(org.springframework.boot.SpringApplication),它在初始化应用上下文时,添加了很多默认的BFPP类。

// org.springframework.boot.SpringApplication#prepareContext
if (this.lazyInitialization) {context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));



2. 自动注册

也可以通过添加组件注解(如@Component)由IoC容器来自动注册后处理器,Spring会自动管理已经注册的所有BFPP类。

实现自动注册也很简单,添加组件注解即可:

@Component
public class SimpleBfPostProcessor implements BeanDefinitionRegistryPostProcessor, Ordered {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {// 注册BeanDefinition等相关内容RootBeanDefinition rbd = new RootBeanDefinition(ConfigBeanServiceImpl.class);registry.registerBeanDefinition("beanName", rbd);}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {// 修改beanFactory内容,一般用于修改BeanDefinition的内容String propertyName = "name";BeanDefinition bd = beanFactory.getBeanDefinition("beanName");MutablePropertyValues propertyValues = bd.getPropertyValues();if (!propertyValues.contains(propertyName)) {propertyValues.add(propertyName, "BeanFactoryPostProcessor-Property-Value");}}@Overridepublic int getOrder() {// 执行的优先级序号return Ordered.LOWEST_PRECEDENCE;}
}

在配置类中注入Bean和组件注解的作用相同:

@Configuration
public class PostProcessorConfig {@Beanpublic static SimpleBfPostProcessor simpleBfPostProcessor() {return new SimpleBfPostProcessor();}
}

有趣的是,配置类@Configuration的扫描和注册Bean的功能就是通过BeanDefinitionRegistryPostProcessor来实现的。所以你可以在配置类中使用@Bean@ComponentScans等等注解来实现注册Bean定义的功能。相关实现可以参考org.springframework.context.annotation.ConfigurationClassPostProcessor源码。



3. 优先级

看过源码的都会注意到,BFPP其实是有执行优先级的,根据源码,我把优先级分为如下几种类型:

提示:
interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor
interface PriorityOrdered extends Ordered

  1. 根据注册方式:手动注册 > 自动注册
  2. 根据注册顺序:先注册 > 后注册
  3. 根据实现类型:BeanDefinitionRegistryPostProcessor > BeanFactoryPostProcessor
  4. 根据排序接口:PriorityOrdered > Ordered > 无排序(无排序时根据注入顺序)
  5. 根据排序序号:Integer.MIN_VALUE > Integer.MAX_VALUE

根据上面的优先级类型,我们排列出一个完整的优先级

出于美观考虑,简化一些写法

  • 把执行BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 方法简化为:BDRPP#registry
  • 把执行BeanDefinitionRegistryPostProcessor#postProcessBeanFactory 方法简化为:BDRPP#beanfactory
  • 把执行BeanFactoryPostProcessor#postProcessBeanFactory 方法简化为: BFPP#beanfactory
  1. 手动注册 + BDRPP#registry
  2. 自动注册 + BDRPP#registry+ PriorityOrdered
  3. 自动注册 + BDRPP#registry+ Ordered
  4. 自动注册 + BDRPP#registry+ 无排序
  5. 手动注册 + BDRPP#beanfactory
  6. 手动注册 + BFPP#beanfactory
  7. 自动注册 + BDRPP#beanfactory(根据BDRPP#Registry的执行顺序)
  8. 自动注册 + BFPP#beanfactory
  9. 自动注册 + BFPP#beanfactory
  10. 自动注册 + BFPP#beanfactory+ 无排序

对于BDRPP#registry方法,如果高优先级注册了新的BDRPP定义,那么这个新的BDRPP会在次一级的优先级中执行。比如:在配置类中通过@Bean注入了新的BDRPP,由于配置类后处理器ConfigurationClassPostProcessor的优先级为PriorityOrdered,那么由配置类注入的新BDRPP(PriorityOrdered或Ordered)将在下一级优先级Ordered中执行,无排序类型同理。无排序优先级的内容将会循环执行,直到没有新的BDRPP定义产生。

这一节的内容绕是绕了点,不过如果需要自己实现BFPP的话,那么了解这些是非常有必要的,因为不同优先级的BFPP的作用范围不同,高优先级BFPP将会影响低优先级的表现,或者低优先级会覆盖高优先级的操作。所以如果你的BFPP不起作用的话可以先看看是否受到优先级影响。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/145834.shtml

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

相关文章

物联网AI MicroPython学习之语法UART通用异步通信

学物联网,来万物简单IoT物联网!! UART 介绍 模块功能: UART通过串行异步收发通信 接口说明 UART - 构建UART对象 函数原型:UART(id, baudrate,bits, parity,stop, tx, rx)参数说明: 参数类…

3GPP协议解读(一)_23.501_23.502_PDU Session_SMF与UDP的交互

UE发起计算服务申请后,网络侧处理的流程 UE发起服务的流程:service request网络侧处理服务涉及的通信数据通过PDU Session进行传输,涉及到SMF与UPF的交互。PDU Session的建立、管理全部由SMF(Session Management Function&#x…

基于JavaWeb+SpringBoot+掌上社区疫苗微信小程序系统的设计和实现

基于JavaWebSpringBoot掌上社区疫苗微信小程序系统的设计和实现 源码获取入口前言主要技术系统设计功能截图Lun文目录订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码获取入口 前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种…

windows使用lcx端口转发登陆远程主机

1.编译lcx源码: GitHub - UndefinedIdentifier/LCX: 自修改免杀lcx端口转发工具 2.在win7上安装vs2010并编译生成lcx.exe 3.在要被控制主机上运行: lcx -slave 192.168.31.248 51 192.168.31.211 3389 192.168.31.248为远程主控制主机,51为远程主机端口 192.168.31.211为被…

C语言--写一个函数返回bool值,来判断给定的字符串A和B(假设都是小写字母),是否是B中的字符都存在于A中,如果是返回true,否则返回false

一.题目描述 写一个函数返回bool值,来判断给定的字符串A和B(假设都是小写字母),是否是B中的字符都存在于A中,如果是返回true,否则返回false。例如: 字符串A:abcde 字符串B&#xff…

顶部动态菜单栏的使用

效果图 开发环境 vue3 关键逻辑 //导航栏状态选择 const navbarSolid ref(false); //初始化导航栏高度 const navbarHeight ref(0);/*** 根据滚动距离改变样式*/ function checkNavbarOpacity() {navbarSolid.value window.pageYOffset > navbarHeight.value / 2; }/**…

html使用天地图写一个地图列表

一、效果图&#xff1a; 点击左侧地址列表&#xff0c;右侧地图跟着改变。 二、代码实现&#xff1a; 一进入页面时&#xff0c;通过body调用onLoad"onLoad()"函数&#xff0c;确保地图正常显示。 <body onLoad"onLoad()"><!--左侧代码-->…

Python入门简介及下载安装,超详细教学!

文章目录 一、Python简介&#xff1a;Python解释器的类型Python的运行机制1、查看 Python 版本2、第一个Python3.x程序3、Python 应用 二、Python安装&#xff08;windows&#xff09;1、下载2、安装步骤&#xff1a; 三、运行Python1、交互式解释器&#xff1a;扩展&#xff1…

鸿蒙LiteOs读源码教程+向LiteOS中添加一个系统调用

本文分为2个部分&#xff1a;第1部分简要介绍如何读鸿蒙Liteos源码&#xff0c;第2部分是实验向LiteOS中添加一个系统调用的完整过程。 前置资料&#xff1a; imx6ull开发板使用方式详解 源码下载 编译运行简单程序 Ubuntu虚拟机使用鸿蒙LiteOs操作系统常见错误汇总 一、鸿…

在Qt设计师(Qt Designer )控件面板加入自定义控件

目录 1. 问题的提出 2. 本次开发环境说明 3. 具体实现 4. 注意的问题 5. 参考链接 1. 问题的提出 在Qt开发中&#xff0c;经常利用Qt设计师&#xff08;Qt Designer &#xff09;把界面设计好&#xff0c;将界面放到ui文件中&#xff0c;将逻辑处理放到cpp文件中&#xff…

计算机视觉基础(9)——相机标定与对极几何

前言 本节我们将学习相机标定和对极几何两部分的内容。 在相机标定部分&#xff0c;我们将学习直接线性变换&#xff08;Direct Linear Transform, DL&#xff09;,张正友标定法&#xff08;Zhang’s Method&#xff09;和 Perspective-n-Point (PnP) 这三种方法。 在对极几何部…

SpringJDBC模板类JdbcTemplate

Spring JdbcTemplate使用JdbcTemplate完成增删改查环境准备新增修改删除查询一个对象批量添加批量修改和批量删除使用德鲁伊连接池&#xff08;之前数据源是用我们自己写的&#xff09; JdbcTemplate JdbcTemplate是Spring提供的一个JDBC模板类&#xff0c;是对JDBC的封装&…

某60区块链安全之51%攻击实战学习记录

区块链安全 文章目录 区块链安全51%攻击实战实验目的实验环境实验工具实验原理攻击过程 51%攻击实战 实验目的 1.理解并掌握区块链基本概念及区块链原理 2.理解区块链分又问题 3.理解掌握区块链51%算力攻击原理与利用 4.找到题目漏洞进行分析并形成利用 实验环境 1.Ubuntu1…

2023数维杯国际赛数学建模竞赛选题建议及B题思路讲解

大家好呀&#xff0c;2023年第九届数维杯国际大学生数学建模挑战赛今天早上开赛啦&#xff0c;在这里先带来初步的选题建议及思路。 目前团队正在写B题和D题完整论文&#xff0c;后续还会持续更新哈&#xff0c;大家三连关注一下防止迷路。 注意&#xff0c;本文只是比较简略…

企业微信获取第三方应用凭证

上一篇介绍了如何配置通用开发参数及通过url回调验证&#xff0c; 本篇将通过服务商后台配置关联小程序应用配置和获取第三方凭证及如何配置企业可信IP。 当然上篇配置的回调设置也不会白费&#xff0c;在下方的指令和数据回调会用到。 第三方应用开发流程 官方企业微信第三方…

Beego之Bee工具使用

1、bee工具使用 bee 工具是一个为了协助快速开发 Beego 项目而创建的项目&#xff0c;通过 bee 你可以很容易的进行 Beego 项目的创 建、热编译、开发、测试、和部署。Bee工具可以使用的命令&#xff1a; [rootzsx ~]# bee 2023/02/18 18:17:26.196 [D] init global config…

van-dialog弹窗异步关闭-校验表单

van-dialog弹窗异步关闭 有时候我们需要通过弹窗去处理表单数据&#xff0c;在原生微信小程序配合vant组件中有多种方式实现&#xff0c;其中UI美观度最高的就是通过van-dialog嵌套表单实现。 通常表单涉及到是否必填&#xff0c;在van-dialog的确认事件中直接return是无法阻止…

软件测试面试-如何定位线上出现bug

其实无论是线上还是在测试出现bug&#xff0c;我们核心的还是要定位出bug出现的原因。 定位出bug的步骤&#xff1a; 1&#xff0c;如果是必现的bug&#xff0c;尽可能的复现出问题&#xff0c;找出引发问题的操作步骤。很多时候&#xff0c;一个bug的产生&#xff0c;很多时…

Java基础笔记

1.数据类型在java语言中包括两种: 第一种:基本数据类型 基本数据类型又可以划分为4大类8小种: 第一类:整数型 byte , short,int, long(没有小数的&#xff09; 第二类:浮点型 float,aouble(带有小数的&#xff09; 第三类:布尔型 boole…

计算机毕业设计 基于Vue的米家商城系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…