由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. 加载与执行

方式有两种:

  1. 利用 ConfigurableApplicationContext 接口的 addBeanFactoryPostProcessor 方法。

    Ngbatis 的加载方式就是利用第一种,在 ApplicationContextInitializer 接口的实现类的 initialize 方法中直接调用 addBeanFactoryPostProcessor 。关于 ApplicationContextInitializer 接口的使用和原理,可以参考上一篇文章: ApplicationContextInitializer接口类的使用和原理解读。

  2. 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想到的更多相关文章

  1. SpringBoot源码学习1——SpringBoot自动装配源码解析+Spring如何处理配置类的

    系列文章目录和关于我 一丶什么是SpringBoot自动装配 SpringBoot通过SPI的机制,在我们程序员引入一些starter之后,扫描外部引用 jar 包中的META-INF/spring. ...

  2. SpringBoot源码学习3——SpringBoot启动流程

    系列文章目录和关于我 一丶前言 在 <SpringBoot源码学习1--SpringBoot自动装配源码解析+Spring如何处理配置类的>中我们学习了SpringBoot自动装配如何实现 ...

  3. Dubbo源码学习--优雅停机原理及在SpringBoot中遇到的问题

    Dubbo源码学习--优雅停机原理及在SpringBoot中遇到的问题 相关文章: Dubbo源码学习文章目录 前言 主要是前一阵子换了工作,第一个任务就是解决目前团队在 Dubbo 停机时产生的问题 ...

  4. 源码学习系列之SpringBoot自动配置(篇一)

    源码学习系列之SpringBoot自动配置源码学习(篇一) ok,本博客尝试跟一下Springboot的自动配置源码,做一下笔记记录,自动配置是Springboot的一个很关键的特性,也容易被忽略的属 ...

  5. 源码学习系列之SpringBoot自动配置(篇二)

    源码学习系列之SpringBoot自动配置(篇二)之HttpEncodingAutoConfiguration 源码分析 继上一篇博客源码学习系列之SpringBoot自动配置(篇一)之后,本博客继续 ...

  6. SpringBoot源码学习系列之SpringMVC自动配置

    目录 1.ContentNegotiatingViewResolver 2.静态资源 3.自动注册 Converter, GenericConverter, and Formatter beans. ...

  7. SpringBoot源码学习系列之异常处理自动配置

    SpringBoot源码学习系列之异常处理自动配置 1.源码学习 先给个SpringBoot中的异常例子,假如访问一个错误链接,让其返回404页面 在浏览器访问: 而在其它的客户端软件,比如postm ...

  8. SpringBoot源码学习系列之嵌入式Servlet容器

    目录 1.博客前言简单介绍 2.定制servlet容器 3.变换servlet容器 4.servlet容器启动原理 SpringBoot源码学习系列之嵌入式Servlet容器启动原理 @ 1.博客前言 ...

  9. SpringBoot源码学习系列之启动原理简介

    本博客通过debug方式简单跟一下Springboot application启动的源码,Springboot的启动源码是比较复杂的,本博客只是简单梳理一下源码,浅析其原理 为了方便跟源码,先找个Ap ...

  10. Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

    Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...

随机推荐

  1. 全流程机器视觉工程开发(一)环境准备,paddledetection和labelme

    前言 我现在在准备做一个全流程的机器视觉的工程,之前做了很多理论相关的工作.大概理解了机器视觉的原理,然后大概了解了一下,我发现现在的库其实已经很发展了,完全不需要用到非常多的理论,只需要知道开发过程 ...

  2. C语言基础之基础的输入输出

    前言 学一门编程语言,不能编写让用户输入数据然后输出处理后的数据的程序那么就等于没学,而在C语言中可以用printf() 和 scanf() 函数进行输入和输出操作.这两个函数是内置的库函数,定义在 ...

  3. 分享Go书籍-《Go Web编程》

    大家好,我是沙漠尽头的狼. 最近几天在看一本Go的书籍,看了100来页,感觉不错,分享给大家​.​ 书籍基本信息 书籍信息: 书名:Go Web编程 作 者:(新加坡)郑兆雄(Sau Sheong C ...

  4. 星索称重/生产管理软件 联机版V1.0

    星索称重/生产管理软件 联机版V1.0   一.特点 1.支持多用户.多组织管理,灵活控制用户权限. 2.支持地磅秤.智能电子秤.轨道秤等多款称重设备. 3.支持三联单/热敏纸等多种打印模板. 二.系 ...

  5. java - 对象装载数据传递到方法中

    1. 创建 Phone 类 package class_object; public class Phone { String brand; String color; double price; v ...

  6. [转帖]SQL Server索引的维护 - 索引碎片、填充因子

    https://www.cnblogs.com/kissdodog/archive/2013/06/14/3135412.html 这两个问题都和页密度有关,虽然两者的表现形式在本质上有所区别,但是故 ...

  7. [转帖]使用 Grafana 监控 TiDB 的最佳实践

    https://docs.pingcap.com/zh/tidb/stable/grafana-monitor-best-practices 使用 TiUP 部署 TiDB 集群时,如果在拓扑配置中添 ...

  8. [转帖]ipset详解

    https://zhuanlan.zhihu.com/p/489103374 ipset创建:create 创建一个新的ipset集合:ipset create SETNAME TYPENAME SE ...

  9. ESXi规避ESXiArgs勒索软件的简单方法

    摘要 今天查看深信服科技的公众号 发现有一个ESXiArgs 的勒索软件. 感觉对公司存在一定的风险.但是感觉操作手册有点简单. 这里想着写全面一点. 作为操作手册使用. 并且深信服仅是解决了在运行, ...

  10. Harbor 简要安装说明

    Harbor 简要安装说明 下载最新的离线安装文件 链接:https://pan.baidu.com/s/1ZEjgnI3YmhsdVOm7h7SWcQ 提取码:GSNB 复制这段内容后打开百度网盘手 ...