[Ngbatis源码学习][SpringBoot] 由BeanFactoryPostProcessor想到
由BeanFactoryPostProcessor想到
在看Ngbatis源码时看到了对BeanFactoryPostProcessor后置处理器的使用,对其的使用并不是很了解,在此做一些学习和总结。
1. 相关类
- BeanFactoryPostProcessor
- BeanDefinitionRegistryPostProcessor
- BeanPostProcessor
2. BeanFactoryPostProcessor
2.1. 作用
BeanFactoryPostProcessor 的主要目的是在Bean实例化前对Bean的配置元数据,也就是对BeanDefinition进行修改操作。
在 Spring 中,所有的 Beans 在被完全实例化之前都是以 BeanDefinition 的形式存在的。
BeanFactoryPostProcessor 能够在Bean完全实例化之前调整和修改这些 BeanDefinition,对 BeanDefinition 的任何修改都会影响后续的 Bean 实例化和初始化过程。
2.2. 加载与执行
方式有两种:
利用
ConfigurableApplicationContext接口的addBeanFactoryPostProcessor方法。Ngbatis 的加载方式就是利用第一种,在 ApplicationContextInitializer 接口的实现类的 initialize 方法中直接调用 addBeanFactoryPostProcessor 。关于 ApplicationContextInitializer 接口的使用和原理,可以参考上一篇文章: ApplicationContextInitializer接口类的使用和原理解读。
org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors方法中扫描实现了 BeanFactoryPostProcessor 接口的 Bean 自动加载。
BeanFactoryPostProcessor 的加载调用涉及到了十分核心的 org.springframework.context.support.AbstractApplicationContext#refresh --> org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors 方法。
第二种方式的调用实现用一张时序图来表现:

2.2.1 扩展知识
BeanFactoryPostProcessor 的加载得对 AbstractApplicationContext 的有关接口进行一个介绍。
放一张UML图在这里:

可以看到, AbstractApplicationContext 实现了 ConfigurableApplicationContext 接口,ConfigurableApplicationContext 接口又继承自 ApplicationContext,ApplicationContext 又扩展了 BeanFactory 的功能。它们之间的关系如上图。归根结底都是帮助我们在管理 Bean。
因为这里这部分不是重点内容,所以只简单说一下他们的作用与区别:
BeanFactory:BeanFactory 与 ApplicationContext 存在派生关系,它是 IOC 的核心接口,虽然没有具体实现但定义了 IOC 容器最基本的规范,其他具体的容器都是通过实现 BeanFactory 的基础上,再进行功能扩展。BeanFactory 是典型的工厂模式的工厂接口。从它的方法中可以看出只提供了获取和判断的方法。

ApplicationContext:在 BeanFactory 的基础上进行了功能扩展,除了间接实现了 BeanFactory 还实现了其他的接口,提供了更多面向实际应用的功能,比如国际化、监听器等。是一个更高级的容器。
ConfigurableApplicationContext:ConfigurableApplicationContext 是 ApplicationContext 的子接口,它在 ApplicationContext 的基础上添加了一系列配置应用上下文的功能。里面就包括了,接下来会说的很重要的添加后置处理器的方法:addBeanFactoryPostProcessor。
AbstractApplicationContext:实现了 ConfigurableApplicationContext 接口,且通过模板方法的设计模式,实现了所有应用上下文的通用方法,其中包括了十分重要的refresh()方法,是很重要的一个类。里面实现了包括最重要的容器初始化操作 refresh 方法、Bean 的生成和获取、监听器的添加等等。因为这个类的方法太多了,在此就不贴图了,有兴趣的小伙伴可以自行查看源码。
3. BeanDefinitionRegistryPostProcessor
3.1. 作用
BeanDefinitionRegistryPostProcessor 是 Spring 容器的一个扩展点,继承自 BeanFactoryPostProcessor,它提供了更为深入的方式来干预bean定义的注册过程。主要用于在 Spring 容器完成对 Bean 的定义信息的加载后、但在它们真正实例化之前,进行额外的操作。
它的特殊之处在于,除了能够像 BeanFactoryPostProcessor 那样修改已经注册的bean定义(BeanDefinition),还能向注册中心 BeanDefinitionRegistry 中动态地添加或移除bean定义。
可以看下 BeanDefinitionRegistryPostProcessor 的源码:
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;
}
从源码注释中可以看出来,它的执行时机是在 BeanFactoryPostProcessor 之前的阶段,对 Bean 的定义信息进行一些操作。
3.2. 加载与执行
BeanDefinitionRegistryPostProcessor 的加载与执行时序图与 BeanFactoryPostProcessor 差不多,在此基础上再加点内容就好。

从时序图中可以看到,BeanDefinitionRegistryPostProcessor 的执行在 BeanFactoryPostProcessor 之前,这也是他们的关键区别。另一个关键区别就是 BeanDefinitionRegistryPostProcessor 可以对 Bean 定义进行增删改操作,而 BeanFactoryPostProcessor 只能对 Bean 定义进行修改操作。
4. BeanPostProcessor
4.1. 作用
BeanPostProcessor是对bean实例生效的,相对于对BeanDefinition的处理,这个阶段更加靠后,BeanPostProcessor处理的时候已经生成了实例对象,BeanPostProcessor会在对象的实例基础上进行一个更进一步的加工。
BeanPostProcessor除了能对Bean进行深加工外,还能直接进行Bean替换,Spring AOP的功能就是这样实现的,把经过代理的Bean放了进去,替换了原有的Bean。
5. 区别与对比
三种后期处理器的执行时机用一张流程图来表示:

三种后置处理器的对比
| 后置处理器 | 处理目标 | 执行时机 | 主要操作 |
|---|---|---|---|
| BeanDefinitionRegistryPostProcessor | 针对BeanDefinitionRegistry(来自各种配置源) | 在所有BeanDefinition被加载和注册之后,在BeanFactoryPostProcessor执行之前 | 向BeanDefinitionRegistry注册、修改、删除BeanDefinition |
| BeanFactoryPostProcessor | 针对BeanDefinition(Bean的配置元数据) | 在所有BeanDefinition被加载和注册之后,在Bean实例化和初始化之前 | 修改已注册的BeanDefinition,包括修改属性、改变类的定义等 |
| BeanPostProcessor | 针对已经实例化,但未完全初始化的Bean对象 | 在Bean初始化过程中,具体是在Bean生命周期的初始化方法前后执行 | 主要用于在Bean初始化前后,比如修改Bean属性,生成代理对象等。 |
[Ngbatis源码学习][SpringBoot] 由BeanFactoryPostProcessor想到的更多相关文章
- SpringBoot源码学习1——SpringBoot自动装配源码解析+Spring如何处理配置类的
系列文章目录和关于我 一丶什么是SpringBoot自动装配 SpringBoot通过SPI的机制,在我们程序员引入一些starter之后,扫描外部引用 jar 包中的META-INF/spring. ...
- SpringBoot源码学习3——SpringBoot启动流程
系列文章目录和关于我 一丶前言 在 <SpringBoot源码学习1--SpringBoot自动装配源码解析+Spring如何处理配置类的>中我们学习了SpringBoot自动装配如何实现 ...
- Dubbo源码学习--优雅停机原理及在SpringBoot中遇到的问题
Dubbo源码学习--优雅停机原理及在SpringBoot中遇到的问题 相关文章: Dubbo源码学习文章目录 前言 主要是前一阵子换了工作,第一个任务就是解决目前团队在 Dubbo 停机时产生的问题 ...
- 源码学习系列之SpringBoot自动配置(篇一)
源码学习系列之SpringBoot自动配置源码学习(篇一) ok,本博客尝试跟一下Springboot的自动配置源码,做一下笔记记录,自动配置是Springboot的一个很关键的特性,也容易被忽略的属 ...
- 源码学习系列之SpringBoot自动配置(篇二)
源码学习系列之SpringBoot自动配置(篇二)之HttpEncodingAutoConfiguration 源码分析 继上一篇博客源码学习系列之SpringBoot自动配置(篇一)之后,本博客继续 ...
- SpringBoot源码学习系列之SpringMVC自动配置
目录 1.ContentNegotiatingViewResolver 2.静态资源 3.自动注册 Converter, GenericConverter, and Formatter beans. ...
- SpringBoot源码学习系列之异常处理自动配置
SpringBoot源码学习系列之异常处理自动配置 1.源码学习 先给个SpringBoot中的异常例子,假如访问一个错误链接,让其返回404页面 在浏览器访问: 而在其它的客户端软件,比如postm ...
- SpringBoot源码学习系列之嵌入式Servlet容器
目录 1.博客前言简单介绍 2.定制servlet容器 3.变换servlet容器 4.servlet容器启动原理 SpringBoot源码学习系列之嵌入式Servlet容器启动原理 @ 1.博客前言 ...
- SpringBoot源码学习系列之启动原理简介
本博客通过debug方式简单跟一下Springboot application启动的源码,Springboot的启动源码是比较复杂的,本博客只是简单梳理一下源码,浅析其原理 为了方便跟源码,先找个Ap ...
- Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...
随机推荐
- 机器学习-决策树系列-Adaboost算法-集成学习-29
目录 1. adaboost算法的基本思想 2. 具体实现 1. adaboost算法的基本思想 集成学习是将多个弱模型集成在一起 变成一个强模型 提高模型的准确率,一般有如下两种: bagging: ...
- idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql
本文为博主原创,未经允许不得转载: mybatis plus 使用过程中已经很大程度提升了我们开发的效率,因为它内部已经对单表的操作进行了完美的封装,但是关联表操作时, 这时就需要自己定义sql,自定 ...
- Java之利用openCsv导出csv文件
当时导入的时候用的openCsv,那么导出的时候自然也是用这个,查了好多资料才找到解决方案,下面记录一下实现过程. 1.Controller层: /** * 导出csv文件 */ @RequestMa ...
- java - Array 数组反序输出
通过Array类的静态 sort() 方法可实现对数组排序,sort() 方法提供了许多种重载形式,可对任意类型数组进行升序排序. 然而,Array类中没有类似 js 的 reverse 反序输出 ...
- c# 编写 WebAssembly
创建一个.net 7.0类库工程,引用下面的nuget包: <PackageReference Include="Microsoft.AspNetCore.Components.Web ...
- CAP-BASE
- 百度网盘(百度云)SVIP超级会员共享账号每日更新(2023.11.22)
一.百度网盘SVIP超级会员共享账号 可能很多人不懂这个共享账号是什么意思,小编在这里给大家做一下解答. 我们多知道百度网盘很大的用处就是类似U盘,不同的人把文件上传到百度网盘,别人可以直接下载,避免 ...
- cancal报错 config dir not found
替换classpath中间封号两边的值
- Oceanbase部分参数学习与验证
Oceanbase部分参数学习与验证 字符集等参数查看 yum install obclient -y 然后使用客户端连接: obclient -h172.24.110.175 -P2881 -uro ...
- TiKV 服务部署的注意事项
TiKV 服务部署的注意事项 背景 最近发现tikv总是会掉线 不知道是哪里触发了啥样子的bug. 所以想着使用systemd 管理一下, 至少在tikv宕机的时候能够拉起来服务. 二进制文件 pd- ...