Spring后置处理器BeanFactoryPostProcessor与BeanPostProcessor源码解析

这篇具有很好参考价值的文章主要介绍了Spring后置处理器BeanFactoryPostProcessor与BeanPostProcessor源码解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、简介

Spring有两种类型的后置处理器,分别是 BeanFactoryPostProcessorBeanPostProcessor ,这里再贴出我画的 Spring 启动过程,可以看看这两种后置处理器在 Spring 启动过程中位置。

Spring后置处理器BeanFactoryPostProcessor与BeanPostProcessor源码解析,源码学习,Spring,Java,spring,java,后端

1、BeanFactoryPostProcessor

BeanFactoryPostProcessorpostProcessBeanFactory 方法在 Spring 容器启动时被调用,可以对整个容器中的 BeanDefinition (Bean 定义)进行处理,BeanFactoryPostProcessor 还有个子接口 BeanDefinitionRegistryPostProcessor ,其 postProcessBeanDefinitionRegistry 方法也可以对 BeanDefinition 进行处理的,但两个的侧重点不一样, BeanDefinitionRegistryPostProcessor 侧重于创建自定义的 BeanDefinition,而 BeanFactoryPostProcessor 侧重于对已有的 BeanDefinition 进行修改。

2、BeanPostProcessor

BeanPostProcessor 是在 Bean 初始化方法调用前后,对 Bean 进行一些预处理或后处理,这个接口有两个方法,分别是 postProcessBeforeInitializationpostProcessAfterInitialization,分别用来执行预处理和后处理。

二、BeanFactoryPostProcessor 源码解析

处理 BeanFactoryPostProcessor 的源码在哪里呢,我们先找到 Spring 的核心方法 refresh 方法(在 AbstractApplicationContext 类里),在里面找到 invokeBeanFactoryPostProcessors 方法

Spring后置处理器BeanFactoryPostProcessor与BeanPostProcessor源码解析,源码学习,Spring,Java,spring,java,后端

跟进去这个方法

Spring后置处理器BeanFactoryPostProcessor与BeanPostProcessor源码解析,源码学习,Spring,Java,spring,java,后端

在跟进到 PostProcessorRegistrationDelegate 类的 invokeBeanFactoryPostProcessors 方法里,就到了核心处理逻辑了,先列出这个方法的代码

public static void invokeBeanFactoryPostProcessors(
		ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

	// Invoke BeanDefinitionRegistryPostProcessors first, if any.
	Set<String> processedBeans = new HashSet<>();

	if (beanFactory instanceof BeanDefinitionRegistry) {
		BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
		List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
		List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

		for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
			if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
				BeanDefinitionRegistryPostProcessor registryProcessor =
						(BeanDefinitionRegistryPostProcessor) postProcessor;
				registryProcessor.postProcessBeanDefinitionRegistry(registry);
				registryProcessors.add(registryProcessor);
			}
			else {
				regularPostProcessors.add(postProcessor);
			}
		}

		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the bean factory post-processors apply to them!
		// Separate between BeanDefinitionRegistryPostProcessors that implement
		// PriorityOrdered, Ordered, and the rest.
		List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

		// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
		for (String ppName : postProcessorNames) {
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
				processedBeans.add(ppName);
			}
		}
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		registryProcessors.addAll(currentRegistryProcessors);
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
		currentRegistryProcessors.clear();

		// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
		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();

		// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
		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();
		}

		// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
		invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
	}

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

	// Do not initialize FactoryBeans here: We need to leave all regular beans
	// uninitialized to let the bean factory post-processors apply to them!
	String[] postProcessorNames =
			beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

	// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
	// Ordered, and the rest.
	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);
		}
	}

	// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
	invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

	// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
	List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
	for (String postProcessorName : orderedPostProcessorNames) {
		orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
	}
	sortPostProcessors(orderedPostProcessors, beanFactory);
	invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

	// Finally, invoke all other BeanFactoryPostProcessors.
	List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
	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();
}

这段代码比较长,我们可以分成两部分来看,前半部分处理 BeanDefinitionRegistryPostProcessors 接口的实现类,后半部分处理 BeanFactoryPostProcessor 接口的实现类,我们先看 BeanDefinitionRegistryPostProcessors 接口的处理流程

1、BeanDefinitionRegistryPostProcessor 接口实现类的处理流程

首先创建了一个名叫 processedBeansHashSet

Spring后置处理器BeanFactoryPostProcessor与BeanPostProcessor源码解析,源码学习,Spring,Java,spring,java,后端

是为了记录处理过的 PostProcessor 的名字,目的是防止重复处理,然后下面对 beanFactory 的类型进行了判断,如果是 BeanDefinitionRegistry 类型,会有一大段的处理逻辑,如果不是,就调用 invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory); 方法

if (beanFactory instanceof BeanDefinitionRegistry) {
	...
}

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

这个方法,其实就是循环执行所有 PostProcessorpostProcessBeanFactory 方法,我们再来看如果是 BeanDefinitionRegistry 类型,是怎么处理的,先看第一段

Spring后置处理器BeanFactoryPostProcessor与BeanPostProcessor源码解析,源码学习,Spring,Java,spring,java,后端

这一段是将传进来的参数 BeanFactoryPostProcessor 集合进行区分,分成 BeanDefinitionRegistryPostProcessor 类型(后面简称 BDRPP)和非 BeanDefinitionRegistryPostProcessor 类型,其实就是 BeanFactoryPostProcessor 类型(后面简称 BFPP),并执行了 BDRPP 类型的 postProcessBeanDefinitionRegistry 方法,并且,把两种类型分别添加到了两个集合里 registryProcessorsregularPostProcessors,继续往下看

Spring后置处理器BeanFactoryPostProcessor与BeanPostProcessor源码解析,源码学习,Spring,Java,spring,java,后端

这一段,先声明了一个 BDRPP 类型的集合,用于存放在 Spring 容器里找到的 BDRPP,然后从 Spring 容器里找到所有 BDRPP 的名字,循环并找到实现了 PriorityOrdered 接口的 BDRPP,排序,添加到之前定义区分 BDRPPBFPP 的集合 registryProcessors 里,然后执行了这些实现了 PriorityOrdered 接口的 BDRPP postProcessBeanDefinitionRegistry 方法,下面以同样的方式处理实现了 Ordered 接口的 BDRPP,这里先科普下 PriorityOrderedOrdered

PriorityOrdered Ordered 是 Spring 框架中用于定义 Bean 的加载顺序的接口。而 PriorityOrderedOrdered 的子类,实现了这两个接口的类,需要实现一个 getOrder() 方法,返回一个 int 值,这个值越大,优先级就越低,而实现了 PriorityOrdered 接口的 Bean 的加载顺序会优先于实现了 Ordered 接口的Bean,且两者都优先于没实现这两个接口的 Bean

所以,这里先处理的实现了 PriorityOrdered 接口的 BDRPP ,再处理了实现了 Ordered 接口的 BDRPP ,有的人会好奇哦,为什么上面已经调用过一次 beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);,下面为什么还要再调一次,这不是重复代码了吗,其实不是,执行了 BDRPPpostProcessBeanDefinitionRegistry 方法,有可能会产生新的 BDRPP ,所以需要再重新取一次,继续看下面的代码

Spring后置处理器BeanFactoryPostProcessor与BeanPostProcessor源码解析,源码学习,Spring,Java,spring,java,后端

知道了执行了 BDRPPpostProcessBeanDefinitionRegistry 方法,有可能会产生新的 BDRPP ,这段就好理解了,一直循环获取 BDRPP,执行其 postProcessBeanDefinitionRegistry 方法,直到不产生新的 BDRPP 为止

Spring后置处理器BeanFactoryPostProcessor与BeanPostProcessor源码解析,源码学习,Spring,Java,spring,java,后端

最后,因为 BDRPPBFPP 的子类,所以也是需要执行 BFPP 里的 postProcessBeanFactory 方法的,但是 BDRPP 的先执行,BFPP 的后执行。

到此 BDRPP 的处理完了,下面看 BFPP

2、BeanFactoryPostProcessor 接口实现类的处理流程

看完 BeanDefinitionRegistryPostProcessor 之后,BeanFactoryPostProcessor(后面简称 BFPP)的处理流程就比较简单了,先看第一段代码

Spring后置处理器BeanFactoryPostProcessor与BeanPostProcessor源码解析,源码学习,Spring,Java,spring,java,后端

获取 Spring 容器里所有 BFPP 类型的 Bean,然后分成三类,分别是实现了 PriorityOrdered 接口的,实现了 Ordered 接口的,其他(也就是不需要排序的),这里需要注意,因为获取 BFPP 类型的 Bean,会将 BDRPP 类型的也获取到,因为 BDRPPBFPP 的子类嘛,所以之前处理过的 BDRPP 需要跳过,继续看下面

Spring后置处理器BeanFactoryPostProcessor与BeanPostProcessor源码解析,源码学习,Spring,Java,spring,java,后端

这边就很好理解了,按照 PriorityOrdered > Ordered > 其他,的顺序依次执行 postProcessBeanFactory 方法

3、总结

总结一下执行顺序

  1. 先执行了 BeanDefinitionRegistryPostProcessorpostProcessBeanDefinitionRegistry 方法,按照顺序 PriorityOrdered > Ordered > 其他;
  2. 再执行了 BeanDefinitionRegistryPostProcessorpostProcessBeanFactory 方法;
  3. 最后执行 BeanFactoryPostProcessorpostProcessBeanFactory 方法,按照顺序 PriorityOrdered > Ordered > 其他;

三、BeanPostProcessor 源码解析

处理 BeanPostProcessor (后面简称 BPP)的源码在哪里呢,我们知道 BPP 是在 Bean 实例化过程中,init 方法执行前后调用的,入口在 Spring 的核心方法 refresh 方法中的 finishBeanFactoryInitialization(beanFactory); 方法里,里面嵌套很多方法,我们直接来到创建 Bean 的核心方法里,也就是 AbstractAutowireCapableBeanFactory 类的 doCreateBean 方法,在这个方法里找到 exposedObject = initializeBean(beanName, exposedObject, mbd); 这句

Spring后置处理器BeanFactoryPostProcessor与BeanPostProcessor源码解析,源码学习,Spring,Java,spring,java,后端

在对 Bean 进行实例化和属性填充之后,就会执行这个方法,进一步完成 Bean 的初始化,我们看看这个方法

Spring后置处理器BeanFactoryPostProcessor与BeanPostProcessor源码解析,源码学习,Spring,Java,spring,java,后端
可以看到在执行 init 方法前后,分别执行了 applyBeanPostProcessorsBeforeInitializationapplyBeanPostProcessorsAfterInitialization 方法,这两个方法里,循环了所有的 BPP,调用了其 postProcessBeforeInitializationpostProcessAfterInitialization 方法。文章来源地址https://www.toymoban.com/news/detail-541506.html

到了这里,关于Spring后置处理器BeanFactoryPostProcessor与BeanPostProcessor源码解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Jmeter后置处理器——JSON提取器

    目录 1、简介  2、使用步骤         1)添加线程组         2)添加http请求         3) 添加JSON提取器 1、简介         JSON是一种简单的数据交换格式,允许互联网应用程序快速传输数据。JSON提取器可以从JSON格式响应数据中提取数据、简化从JSON原始数据中提取特

    2024年01月16日
    浏览(40)
  • 【JMeter】后置处理器的分类以及场景介绍

    1.常用后置处理器的分类 Json提取器 针对响应体的返回结果是 json格式 的 会自动生成新的变量名为【提取器中 变量名_MatchNr 】,取到的个数由jsonpath expression取到的个数决定 可以当作普通变量调用,调用语法:${ 提取器中 变量名_MatchNr } 正则表达式提取器 返回结果是 任何数

    2024年02月05日
    浏览(52)
  • jmeter-BeanShell预处理器与BeanShell后置处理器的使用

    BeanShell是一个小型嵌入式Java源代码解释器,具有对象脚本语言特性,能够动态地执行标准JAVA语法,并利用在JavaScript和Perl中常见的松散类型、命令、闭包等通用脚本来对其进行拓展。 前置处理器:请求发送之前对请求参数做一些处理 后置处理器:请求发送完成之后对响应数

    2023年04月17日
    浏览(43)
  • 【Jmeter】Request1输出作为Request2输入-后置处理器

    【Jmeter】基础介绍-详细 接上文,继续介绍Jmeter,本文关注点为如何解决上文中提到的第一个问题,即: 需要实现Request1的返回作为Request2的RequestBody或Header Jmeter支持后置处理器,即对http请求(或其他取样器)的返回值进行提取并赋值给变量。 本例中从Request1的ResponseBody中提

    2023年04月20日
    浏览(42)
  • Spring MVC异常处理【单个控制异常处理器、全局异常处理器、自定义异常处理器】

    目录 一、单个控制器异常处理 1.1 控制器方法 1.2 编写出错页面 1.3 测试结果 二、全局异常处理 2.1 一个有异常的控制器类 2.2 全局异常处理器类 2.3 测试结果  三、自定义异常处理器 3.1 自定义异常处理器 3.2 测试结果 往期专栏文章相关导读  1. Maven系列专栏文章 2. Mybatis系列

    2024年02月16日
    浏览(46)
  • Spring Boot 容器扩展BeanFactoryPostProcessor、BeanPostProcessor、 BeanDefinitionRegistryPostProcessor用法和解析

    之所以在企业级应用中Spring 到Spring Boot 一直立于不败之地,保持火热,其中很关键的一个点是,它的扩展简直太强大了,上一篇,我们聊了一下 Spring Boot整个生命周期中的扩展点,,比如 SpringApplicationRunListener 可以监听应用的各个阶段。本文我们聊聊,Spring 容器上的扩展。

    2024年02月11日
    浏览(42)
  • Spring异常处理器

     问题:   程序允许不免的在各层都可能会产生异常,我们该如何处理这些异常? 如果只是在方法里面单独使用 try… catch… 语句去一个一个的进行捕捉处理的话,那毫无疑问是不现实的,因为异常数量是非常庞大的并且对于异常的出现种类是不可预料的,于是我们可以使用

    2024年02月13日
    浏览(46)
  • Spring MVC 异常处理器

    如果不加以异常处理,错误信息肯定会抛在浏览器页面上,这样很不友好,所以必须进行异常处理。 系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图: 编写controller 在index.jsp里面定义超链接

    2024年01月22日
    浏览(45)
  • Spring MVC配置全局异常处理器!!!

    为什么要使用全局异常处理器:如果不加以异常处理,错误信息肯定会抛在浏览器页面上,这样很不友好,所以必须进行异常处理。 系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图: 结果展示:  

    2024年01月15日
    浏览(45)
  • spring框架_常见工厂后处理器

    ConfigurationClassPostProcessor :用于解析@ComponentScan @Bean @Import @ImportResource MapperSacnnerConfigurer :相当于Mybatis的@MapperScanner 用于解析被标注的@Mapper接口 @mapper 注解的解析:@mapper注解是mybatis提供的,用于标明一个接口,spring自然无法管理接口,要将这个接口转化为一个bean加入到beanfa

    2024年02月05日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包