BeanFactoryPostProcessor 接口的英文描述: Allows for custom modification of an application context's bean definitions, adapting the bean property values of the context's underlying bean factory.

允许自定义修改应用程序上下文的 Bean Definitions,修改上下文的基础 bean工厂的 bean 属性值

分析 BeanFactoryPostProcessor ,此接口为 Spring IOC 的一个扩展点。 Spring容器启动过程中,获取 BeanFactory后,会调用该扩展点实现,主要作用是对已加载的 BeanDefinition 进行动态修改。

在解析完成 Bean 定义( XML 或者 JAVA 配置),封装成 BeanDefinition 对象,通过调用 BeanDefinitionRegistry.registry()的过程之后, 容器初始化 Bean 之前的这段时间之间,对已封装好的 Bean 定义 BeanDefinition 进行修改。

简要概括就是 Spring 加载 Bean 整体上分为 注册实例化 两步,在这两步中间执行的逻辑,其中之一就会对实现了 BeanFactoryPostProcessor接口的 Bean 进行操作,这也是 Spring 提供的一个扩展点。

BeanFactoryPostProcessor 扩展点时机

我们查看 AbstractApplicationContextrefresh() 方法

public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// 1  Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// 2  Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// 3  Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// 4  Initialize message source for this context.initMessageSource();// 5  Initialize event multicaster for this context.initApplicationEventMulticaster();// 6  Initialize other special beans in specific context subclasses.onRefresh();// 7  Check for listener beans and register them.registerListeners();// 8  Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// 9  Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}}

refresh() 首先通过 obtainFreshBeanFactory 获取到 BeanFactory 工厂,此处工厂实际为 DefaultListableBeanFactory,该工厂持有已解析的所有的Bean定义 BeanDefinition。refresh 在第二步执行 invokeBeanFactoryPostProcessors。这里主要是执行实现了 BeanFactoryPostProcessor 接口的 bean 对应的 接口方法。

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// ... 省略部分代码
}

PostProcessorRegistrationDelegate 及其子接口的扩展点机制

这里我们引入 BeanFactoryPostProcessor 的子接口BeanDefinitionRegistryPostProcessor。该接口的方法调用会比父接口更早,并且它新增了一个接口方法。定义如下:

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {//在ApplicationContext 标准初始化之后修改其内部bean定义信息。//此时所有常规bean定义都已加载,但还没有实例化bean。// 这允许在下一个后期处理阶段开始之前进一步添加Bean定义void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}

BeanDefinitionRegistryPostProcessor 的作用是,它提供支持注册新的BeanDefiniton (通过 postProcessBeanDefinitionRegistry 方法),并且在下一阶段仍可以被BeanFactoryPostProcessor去修改它的属性值。它在 BeanFactoryPostProcessor 之前执行。

BeanFactoryPostProcessor扩展点实现原理

PostProcessorRegistrationDelegate 核心代码

// ... 省略部分代码
// 执行没有实现 PriorityOrdered 和 Ordered 接口的普通的
// BeanDefinitionRegistryPostProcessor实现类
boolean 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);// 执行 postProcessBeanDefinitionRegistry pp.postProcessBeanDefinitionRegistry(registry);reiterate = true;}}
}
// BeanDefinitionRegistryPostProcessor 执行BeanFactoryPostProcessor接口的方法 postProcessBeanFactory
invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);
// BeanFactoryPostProcessor执行起自身接口方法 postProcessBeanFactory
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
  • 该执行过程在AbstractApplicationContext.refresh()方法中的第二步(try内代码)invokeBeanFactoryPostProcessors执行。
  • 找出BeanFactory中持有的实现了BeanDefinitionRegistryPostProcessor接口的bean定义。
  • 对实现类判断,判断是否实现了排序接口 PriorityOrdered 和 Ordered,如果有,优先执行他们
  • 如果没有找到,执行上文代码块里的逻辑,先call 接口定义的 postProcessBeanDefinitionRegistry,再执行从父接口 BeanFactoryPostProcessor 继承的方法 postProcessBeanFactory
  • BeanDefinitionRegistryPostProcessor执行完之后,最后回去执行实现了BeanFactoryPostProcessor 接口的 bean 的 postProcessBeanFactory 方法 。

BeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor 用途

BeanFactoryPostProcessor 应用

典型应用:PropertySourcesPlaceholderConfigurer
我们非常常用的场景,在xml中配置数据源等信息时,会使用 SpringEL 表达式的形式去占位,然后真正的值会在配置文件中给出,配置如下:

 <!--该类的作用是加载配置文件,然后替换EL表达式-->
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"><property name="location" value="classpath*:application.properties"/>
</bean><!--数据源配置-->
<bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource"init-method="init" destroy-method="close"><property name="url" value="${jdbc_url}"/><property name="username" value="${jdbc_username}"/><property name="password" value="${jdbc_password}"/>
</bean>

其实在 Spring 容器 registryBeanDefinition 时,即还没有初始化 Bean 之前,Bean 定义中的属性值这一块的值仍然是 EL 表达式。

容器在加载好 Bean 定义后,实例化 Bean 之前,会有一个钩子,这个钩子就是上文提到的 BeanFactoryPostProcessorPropertySourcesPlaceholderConfigurer 继承了这个接口,所以它的作用就是动态的替换所有已注册 Bean的BeanDefinition 信息中的 EL 的值为实际配置文件中的值。

BeanDefinitionRegistryPostProcessor 应用

典型应用:MapperScannerConfigurer
MapperScannerConfigurermybatis 整合 Spring 时使用的类。该类主要作用是提供对 mybatis Mapper 类的自动扫包操作,定义此 Bean 之后,通过配置basePackage属性,该类会去扫描相应的包下所有的接口类,然后将这些类的 Bean 定义改造为 MapperFactoryBean。可以有效的避免在 Spring 配置文件中为每一个Mapper注册对应的 MapperFactoryBean 类。

该类可以再 Spring 容器实例化 Bean之前,对已定义的 BeanDefinition 进行 修改。该类会通过 ClassPathMapperScanner 扫描器去扫描 指定 package下面的接口类,然后对这个 BeanDefinition 进行修改,设置它的类型为 MapperFactoryBean
关于为什么 mybatis 要将 Mapper 接口类改造为 MapperFactoryBean ,将在后续文章中进行分析。

总结

BeanFactoryPostProcessor 接口是 Spring IOC 中 一个时机点比较早的扩展点钩子。它优先于 BeanPostProcessor 扩展点 ,我们需要区分这两个扩展点的不同之处。因为它们名字实在是太像了,BeanFactoryPostProcessor 接口的扩展点时机在 IOC 容器加载完成所有 BeanDefinition 后,实例化这些 Bean之前的点。
BeanPostProcessor 的时机点在容器准备开始实例化 Bean 时。BeanPostProcessor 扩展点又有很多的子接口,每一个子接口又处在不同的时机,所以后期分析 BeanPostProcessor 还任重而道远。

转载于:https://www.cnblogs.com/leihuazhe/p/9691701.html

Spring-IOC 扩展点 BeanFactoryPostProcessor及其子接口解析相关推荐

  1. 实现自定义扩展点_spring扩展API接口介绍

    对spring进行定制化功能扩展时,可以选择如下一些扩展点: BeanFactoryPostProcessor 是beanFactory后置处理器,支持在bean factory标准初始化完成后,对b ...

  2. Spring Boot——[JPA 无法注入 JpaRepository 子接口问题]解决方案

    问题描述 Error starting ApplicationContext. To display the conditions report re-run your application wit ...

  3. Spring IOC 核心流程浓缩

    一.基础概念 1.IoC 和 DI IoC (Inversion of Control),即控制反转.这不是一种新的技术,而是 Spring 的一种设计思想. 在传统的程序设计,我们直接在对象内部通过 ...

  4. Spring IoC容器初始化源码(1)—容器初始化入口以及setConfigLocations设置容器配置信息【一万字】

      基于最新Spring 5.x,对于基于XML的Spring IoC容器初始化过程中的setConfigLocations设置容器配置信息方法的源码进行了详细分析,最后给出了比较详细的方法调用时序图 ...

  5. Spring IOC 组件概述

    IOC 概述 IOC: Inversion of Control(控制反转), 这里其实指的是: 将程序中需要使用的 POJOs, 丢入到容器中, 解析成统一的 BeanDefinition(主要基于 ...

  6. Spring —— IoC 容器详解

    引言 本篇博客总结自官网的<The IoC Container>,其中会结合王富强老师的<Spring揭秘>融入自己的语言和理解,争取通过这一篇文章彻底扫除spring IOC ...

  7. Spring IOC:bean的生命周期与@Autowire(1)

    全系列文章: <Spring IOC:bean的生命周期与@Autowire(1)> <Spring IOC:bean的生命周期与@Autowire(2)> <Sprin ...

  8. Spring:源码解读Spring IOC原理

    2019独角兽企业重金招聘Python工程师标准>>> 一.什么是Ioc/DI? IOC容器:主要是完成了 完成对象的创建和依赖的管理注入等. 先从我们自己设计这样一个视角来考虑: ...

  9. Spring IOC流程源码分析

    一.Spring 核心容器 IOC初始化过程 Spring 核心之 IOC 容器初体验 IOC 与 DI IOC(Inversion of Control)控制反转:所谓控制反转,就是把原先我们代码里 ...

  10. 一步一步手绘Spring IOC运行时序图二(基于XML的IOC容器初始化)

    相关内容: 架构师系列内容:架构师学习笔记(持续更新) 一步一步手绘Spring IOC运行时序图一(Spring 核心容器 IOC初始化过程) 一步一步手绘Spring IOC运行时序图二(基于XM ...

最新文章

  1. 教你如何保养iphone电池
  2. week04_python函数返回值、作用域
  3. 职业生涯愿景计算机,职业生涯愿景
  4. ASP.NET MVC Global.cs - 应用程序事件
  5. 飞鸽传书2009绿色版 官方网站下载地址
  6. spring的整体架构分析一
  7. Maven实战读书笔记(3)
  8. 计算机应用基础 东师 离线,东师1609计算机应用基础离线作业(8页)-原创力文档...
  9. 组态王和modbus协议
  10. sql 查询的在northern最大的价值(LAT_N),小于137.2345 ,在小数点后4 位截断
  11. 设计模式-Builder Pattern
  12. 能源路由器:基于固态变压器的能源路由器结构与能源流量模型
  13. LOAP引擎:clickhouse03:文件的导入导出方式
  14. matlab进行预测误差过大,神经网络预测误差太大怎么办,如何看预测结果
  15. SSH-KeyGen -认证密钥的生成、管理和转换
  16. 基于面板数据的熵值法介绍与实现
  17. 中职生计算机系自我推荐作文,中职生自我鉴定
  18. 在html页面引入外部html的方法 (使用第三方插件)
  19. 全网最硬核 JVM TLAB 分析(额外加菜) 8. 通过 JFR 监控 TLAB
  20. 如何在IDEA中创建web项目并且部署到Tomcat中

热门文章

  1. SpringBoot整合RabbitMQ之Fanout Exchange扇形(广播式)交换机(学习总结)
  2. Apache目录禁止解析
  3. 苹果的编程语言--Swift
  4. 《Adobe Illustrator CS6中文版经典教程(彩色版)》—第0课0.14节使用画笔工具
  5. 使用Web Deploy进行远程部署
  6. Sparkline图
  7. 推荐几个学习JS的站点
  8. android mp3文件图片,android 完美获取音乐文件中的专辑图片并显示
  9. GridView里面的Item高度设置
  10. POJ2002 Squares