Spring的BeanFactoryPostProcessor接口示例代码详解

接口简介

BeanFactoryPostProcessor 接口是 Spring 初始化 BeanFactory 时对外暴露的扩展点,Spring IoC 容器允许 BeanFactoryPostProcessor 在容器实例化任何 bean 之前读取 bean 的定义,并可以修改它。

BeanDefinitionRegistryPostProcessor 继承自 BeanFactoryPostProcessor,比 BeanFactoryPostProcessor 具有更高的优先级,主要用来在常规的 BeanFactoryPostProcessor 检测开始之前注册其他 bean 定义。特别是,你可以通过 BeanDefinitionRegistryPostProcessor 来注册一些常规的 BeanFactoryPostProcessor,因为此时所有常规的 BeanFactoryPostProcessor 都还没开始被处理。

注意点:通过BeanDefinitionRegistryPostProcessor 注册的 BeanDefinitionRegistryPostProcessor 接口的postProcessBeanDefinitionRegistry方法将得不到调用,具体的原因会在下面的代码中解释。

BeanFactoryPostProcessor 接口调用机制

BeanFactoryPostProcessor 接口的调用在 AbstractApplicationContext#invokeBeanFactoryPostProcessors方法中。

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

		// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
		// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
		if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}

进入PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors())方法:

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
   // 用于存放已经处理过的Bean名字
		Set<String> processedBeans = new HashSet<>();
   // 一般会进入这个判断
		if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
    // 所谓的regularPostProcessors就是指实现BeanFactoryPostProcessor接口的Bean
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
    // 所谓的registryProcessors就是指实现BeanDefinitionRegistryPostProcessor接口的Bean
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
    // 这边遍历的是通过ApplicationContext接口注册的BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor接口
    // 需要和BeanFactory中BeanDefinitionMap中的BeanFactoryPostProcessor接口区分开
			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
      //如果是BeanDefinitionRegistryPostProcessor,则先进行postProcessBeanDefinitionRegistry处理,这个方法一般进行BeanDefinition注册,从这边可以看出BeanDefinitionRegistryPostProcessor接口的方法先调用,所以优先级高于BeanFactoryPostProcessor
      // 通过这个代码可以看出,通过ApplicationContext直接注册的BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor并不支持Order接口,而是根据注册的顺序执行
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
      // 保存这个BeanDefinitionRegistryPostProcessor,因为还要执行这个类的BeanFactoryPostProcessor方法;
					registryProcessors.add(registryProcessor);
				}
				else {
      // 保存,后面还要执行这个类的BeanFactoryPostProcessor方法;
					regularPostProcessors.add(postProcessor);
				}
			}

			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
    // 这边获取的是BeanFactory中的BeanDefinitionRegistryPostProcessor
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
     //先处理PriorityOrdered标注的BeanDefinitionRegistryPostProcessor
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
      //将其标记为已经处理,防止重复处理
					processedBeans.add(ppName);
				}
			}
    // 将其排序,以便按顺序处理
			sortPostProcessors(currentRegistryProcessors, beanFactory);
    // 将其保存,以便处理这个类的BeanFactoryPostProcessor方法
			registryProcessors.addAll(currentRegistryProcessors);
    // 执行BeanDefinitionRegistryPostProcessor接口方法
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    // 清除,以便开始处理@Order标注的注解
			currentRegistryProcessors.clear();

    // 注意:这边重新获取BeanDefinitionRegistryPostProcessor是有深意的,因为上面在处理@PriorityOrdered标注的BeanDefinitionRegistryPostProcessor时可能又注入了新的BeanDefinitionRegistryPostProcessor。
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
     // 判断是否处理过,防止重复处理,下面的逻辑和上面相同, 不介绍了
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();

    // 处理不标注注解的BeanDefinitionRegistryPostProcessor
			boolean reiterate = true;
			while (reiterate) {
				reiterate = false;
				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
				for (String ppName : postProcessorNames) {
					if (!processedBeans.contains(ppName)) {
						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
						processedBeans.add(ppName);
						reiterate = true;
					}
				}
				sortPostProcessors(currentRegistryProcessors, beanFactory);
				registryProcessors.addAll(currentRegistryProcessors);
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
				currentRegistryProcessors.clear();
			}

			// 调用postProcessBeanFactory 方法,所以BeanDefinitionRegistryPostProcessor中的postProcessBeanFactory方法的优先级要高。
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}

		else {
			// Invoke factory processors registered with the context instance.
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}

		// 开始处理BeanFactoryPostProcessor接口
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

		// 也是按照@PriorityOrdered @Ordered 和普通的方式进行处理
		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
    // 可能已经处理过
			if (processedBeans.contains(ppName)) {
				// skip - already processed in first phase above
			}
			else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}
   // 先执行@PriorityOrdered标注的接口
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
   // 处理@Order标注的类
		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String postProcessorName : orderedPostProcessorNames) {
    // 这边通过名字重新拿了Bean,应该是怕上面的处理改变了Bean
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		// 最后调用普通的BeanFactoryPostProcessor
		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String postProcessorName : nonOrderedPostProcessorNames) {
			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

		// Clear cached merged bean definitions since the post-processors might have
		// modified the original metadata, e.g. replacing placeholders in values...
		beanFactory.clearMetadataCache();
	}

简单总结

上面的方法看起来很长很复杂,但其实干的事情并不多,就调用了BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor接口的实现。这边再简单总结下具体的过程:

step1:执行通过ApplicationContext#addBeanFactoryPostProcessor()方法注册的BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor。

具体过程如下:假如通过ApplicationContext注册了一个BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor,那么会先执行BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,但是BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法和BeanFactoryPostProcessor的postProcessBeanFactory方法暂时都不会在这步执行。

另外需要注意的是:通过ApplicationContext注册的BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor都不支持@PriorityOrdered和@Ordered顺序处理,而是按照我们添加的顺序处理

step2:处理BeanFactory中的BeanDefinitionRegistryPostProcessor,处理的顺序是先处理@PriorityOrdered标注的,再处理@Ordered标注的,最后处理普通的BeanDefinitionRegistryPostProcessor。到这边,所有BeanDefinitionRegistryPostProcessor接口的postProcessBeanDefinitionRegistry方法都已经调用完毕,下面就开始处理BeanFactoryPostProcessor的postProcessBeanFactory方法。

step3:调用BeanDefinitionRegistryPostProcessor实现的postProcessBeanFactory方法(因为BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子接口)

step4:调用通过ApplicationContext#addBeanFactoryPostProcessor()注册的“单纯”的BeanFactoryPostProcessor

step5:调用BeanFactory中的BeanFactoryPostProcessor,调用顺序也是按照@PriorityOrdered和@Ordered顺序处理,没有这两个注解的最后处理。

好了,到这边BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor接口就已经处理完了。后面我们会拿ConfigurationClassPostProcessor 这个特殊的BeanDefinitionRegistryPostProcessor做列子讲下具体流程,这边只是介绍BeanFactoryPostProcessor的调用机制。

到此这篇关于Spring的BeanFactoryPostProcessor接口的文章就介绍到这了,更多相关Spring BeanFactoryPostProcessor接口内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring实战之使用Expression接口进行表达式求值操作示例

    本文实例讲述了Spring使用Expression接口进行表达式求值操作.分享给大家供大家参考,具体如下: 一 Bean package org.crazyit.app.domain; import java.util.Date; public class Person { private Integer id; private String name; private Date birth; // 无参数的构造器 public Person() { } // 初始化全部成员变量的构造器 pub

  • spring boot 统一JSON格式的接口返回结果的实现

    前后端分离的项目开发前,会提前规定好数据返回格式,本文以JSON为例. 第一步,定义好JavaBean. package com.yclouds.myhelper.web.response; import com.fasterxml.jackson.annotation.JsonIgnore; import com.yclouds.myhelper.web.error.code.BaseEnumError; import java.io.Serializable; import lombok.D

  • Spring注解驱动扩展原理BeanFactoryPostProcessor

    1.扩展原理-BeanFactoryPostProcessor BeanFactoryPostProcessor * 扩展原理: * BeanPostProcessor:bean后置处理器,bean创建对象初始化前后进行拦截工作的 * * 1.BeanFactoryPostProcessor:beanFactory的后置处理器: * 在BeanFactory标准初始化之后调用,来定制和修改BeanFactory的内容: * 所有的bean定义已经保存加载到beanFactory,但是bean的实

  • Spring Cloud Feign接口返回流的实现

    服务提供者 @GetMapping("/{id}") public void queryJobInfoLogDetail(@PathVariable("id") Long id, HttpServletResponse response) { File file = new File("xxxxx"); InputStream fileInputStream = new FileInputStream(file); OutputStream ou

  • SpringBoot实现文件上传接口

    摘要 公司都是采用SpringBoot作为项目框架,其实SpringBoot和SSM框架很接近,基本上只是将SSM的一些配置项修改为自动配置或者简单的注解配置就可以了,建议不了解的SpringBoot的朋友们可以了解一下,上手很快,其实文件上传框架根本没有多大关系.我只是顺便帮SpringBoot打个广告罢了. 正题 需求:需要实现一个文件上传的web接口. 1.先实现一个Controller接口,如下: package com.lanxuewei.utils.aspect; import co

  • Spring的BeanFactoryPostProcessor接口示例代码详解

    接口简介 BeanFactoryPostProcessor 接口是 Spring 初始化 BeanFactory 时对外暴露的扩展点,Spring IoC 容器允许 BeanFactoryPostProcessor 在容器实例化任何 bean 之前读取 bean 的定义,并可以修改它. BeanDefinitionRegistryPostProcessor 继承自 BeanFactoryPostProcessor,比 BeanFactoryPostProcessor 具有更高的优先级,主要用来在

  • Spring Aware接口示例代码详解

    若 Spring 检测到 bean 实现了 Aware 接口,则会为其注入相应的依赖.所以通过让bean 实现 Aware 接口,则能在 bean 中获得相应的 Spring 容器资源. Spring 中提供的 Aware 接口有: BeanNameAware:注入当前 bean 对应 beanName BeanClassLoaderAware:注入加载当前 bean 的 ClassLoader BeanFactoryAware:注入 当前BeanFactory容器 的引用 BeanNameAw

  • Spring Boot加密配置文件特殊内容的示例代码详解

    有时安全不得不考虑,看看新闻泄漏风波事件就知道了我们在用Spring boot进行开发时,经常要配置很多外置参数ftp.数据库连接信息.支付信息等敏感隐私信息,如下 ​ 这不太好,特别是互联网应用,应该用加密的方式比较安全,有点类似一些应用如电商.公安.安检平台.滚动式大屏中奖信息等显示身份证号和手机号都是前几位4109128*********和158*******.那就把图中的明文改造下1. 引入加密包,可选,要是自己实现加解密算法,就不需要引入第三方加解密库 <dependency> &l

  • spring实现bean对象创建代码详解

    我以一个简单的示例解构spring是怎样管理java对象的. 首先,定义一个简单的pojo,代码如下: package com.jvk.ken.spring; public class Demo { private String name; public Demo() { name="I'm Demo."; } public void printName() { System.out.println(name); } public void setName(String name) {

  • Laravel 5.5 的自定义验证对象/类示例代码详解

    Laravel 5.5 将提供一个全新的自定义验证规则的对象,以作为原来的 Validator::extend 方法的替代. Laravel 5.5 将提供一个全新的自定义验证规则的对象,以作为原来的 Validator::extend 方法的替代..很多时候我们会直接用正则表达式来处理这种特殊的验证,也有时候我们会选择用 Validator::extend 来扩展一个自定义的规则.但在 Laravel 5.5 版本中,我们有了新的手段,只要定义一个实现 Illuminate\Contracts

  • springboot多数据源配置及切换的示例代码详解

    注:本文的多数据源配置及切换的实现方法是,在框架中封装,具体项目中配置及使用,也适用于多模块项目 配置文件数据源读取 通过springboot的Envioment和Binder对象进行读取,无需手动声明DataSource的Bean yml数据源配置格式如下: spring: datasource: master: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver url:

  • 微信小程序 获取手机号 JavaScript解密示例代码详解

    当我们在开发微信小程序中,有一个常用的功能,就是获取用户的手机号,然后一键登入小程序,那么手机号如何获取呢?请认真看完本文,保证可以获取到用户的手机号. 刚开始开发微信小程序的时候,想着实现手机验证码登入,后来查阅资料得知,发给用户的短信是要自己付费的.后来想想,微信获取用户的手机号一样可以保证手机号码的真实性,因为手机号既然可以绑定微信,那么肯定是被严格核验过的,然后就开始了获取手机号之旅,网上教程有很多,但不知什么原因,都是会少一些内容,有的只有前端代码,没有后端:有的后端代码是PHP,不是

  • Spring实例化bean的方式代码详解

    通过这篇文章通过实例代码向大家介绍了Spring实例化bean的几种方法,接下来看看具体内容吧. 1.使用类构造器实现实例化(bean的自身构造器) <bean id = "orderService" class="cn.itcast.OrderServiceBean"/> 2.使用静态工厂方法实现实例化 <bean id = "personService" class = "cn.itcast.OrderFactor

  • Java的静态类型检查示例代码详解

    关于静态类型检查和动态类型检查的解释: 静态类型检查:基于程序的源代码来验证类型安全的过程: 动态类型检查:在程序运行期间验证类型安全的过程: Java使用静态类型检查在编译期间分析程序,确保没有类型错误.基本的思想是不要让类型错误在运行期间发生. 在各色各样的编程语言中,总共存在着两个类型检查机制:静态类型检查和动态类型检查. 静态类型检查是指通过对应用程序的源码进行分析,在编译期间就保证程序的类型安全. 动态类型检查是在程序的运行过程中,验证程序的类型安全.在Java中,编译期间使用静态类型

  • Vue创建头部组件示例代码详解

    Vue.js 组件 组件(Component)是 Vue.js 最强大的功能之一. 组件可以扩展 HTML 元素,封装可重用的代码. 具体代码如下所示: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title

随机推荐