由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. 机器学习-决策树系列-Adaboost算法-集成学习-29

    目录 1. adaboost算法的基本思想 2. 具体实现 1. adaboost算法的基本思想 集成学习是将多个弱模型集成在一起 变成一个强模型 提高模型的准确率,一般有如下两种: bagging: ...

  2. idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql

    本文为博主原创,未经允许不得转载: mybatis plus 使用过程中已经很大程度提升了我们开发的效率,因为它内部已经对单表的操作进行了完美的封装,但是关联表操作时, 这时就需要自己定义sql,自定 ...

  3. Java之利用openCsv导出csv文件

    当时导入的时候用的openCsv,那么导出的时候自然也是用这个,查了好多资料才找到解决方案,下面记录一下实现过程. 1.Controller层: /** * 导出csv文件 */ @RequestMa ...

  4. java - Array 数组反序输出

    通过Array类的静态 sort() 方法可实现对数组排序,sort() 方法提供了许多种重载形式,可对任意类型数组进行升序排序. 然而,Array类中没有类似 js 的 reverse   反序输出 ...

  5. c# 编写 WebAssembly

    创建一个.net 7.0类库工程,引用下面的nuget包: <PackageReference Include="Microsoft.AspNetCore.Components.Web ...

  6. CAP-BASE

  7. 百度网盘(百度云)SVIP超级会员共享账号每日更新(2023.11.22)

    一.百度网盘SVIP超级会员共享账号 可能很多人不懂这个共享账号是什么意思,小编在这里给大家做一下解答. 我们多知道百度网盘很大的用处就是类似U盘,不同的人把文件上传到百度网盘,别人可以直接下载,避免 ...

  8. cancal报错 config dir not found

    替换classpath中间封号两边的值

  9. Oceanbase部分参数学习与验证

    Oceanbase部分参数学习与验证 字符集等参数查看 yum install obclient -y 然后使用客户端连接: obclient -h172.24.110.175 -P2881 -uro ...

  10. TiKV 服务部署的注意事项

    TiKV 服务部署的注意事项 背景 最近发现tikv总是会掉线 不知道是哪里触发了啥样子的bug. 所以想着使用systemd 管理一下, 至少在tikv宕机的时候能够拉起来服务. 二进制文件 pd- ...