认识Spring 中的BeanPostProcessor

关于BeanPostProcessor和BeanFactoryPostProcessors,将分2篇文章来写,这篇文章是对Spring 中BeanPostProcessor进行了总结

先看下大模型对这个类的介绍,随后再看下这两个类的示例,最后看下这两个类的实现。

这两个类从名字看都很类似,见名知意:BeanPostProcessor=Bean后置处理器,BeanFactoryPostProcessors=BeanFactory后置处理器

BeanPostProcessor

在Spring 5.3中,BeanPostProcessor是一个强大的接口,它允许开发者在Spring容器中的bean实例化、配置和初始化前后添加自定义的逻辑处理。以下是关于BeanPostProcessor的详细解释:

1. 作用阶段
BeanPostProcessor在Spring容器完成bean的实例化、配置和其他的初始化前后工作。它提供了两个方法,一个在初始化方法之前执行,另一个在初始化方法之后执行。
2. 主要方法
postProcessBeforeInitialization(Object bean, String beanName):
在bean的初始化方法(如@PostConstruct标记的方法或实现InitializingBean接口中的afterPropertiesSet方法)被调用之前执行。
允许在bean的属性被设置之后,但在初始化之前,对bean进行额外的处理。
postProcessAfterInitialization(Object bean, String beanName):
在bean的初始化方法被调用之后执行。
允许在bean完成初始化后,对其进行修改或返回一个新的对象(尽管这通常不是推荐的做法,因为可能导致意外的行为)。
3. 返回值
这两个方法都不能返回null。如果返回null,那么在后续的操作中可能会遇到空指针异常,或者通过getBean()方法无法获取到bean的实例。
4. 使用方式
要使用BeanPostProcessor,你需要:
实现BeanPostProcessor接口。
实现postProcessBeforeInitialization和postProcessAfterInitialization方法。
将你的BeanPostProcessor实现注册为Spring容器中的一个bean,这样Spring就能够识别并应用它。
5. 排序和优先级
如果在Spring配置中定义了多个BeanPostProcessor,那么默认情况下,Spring容器会根据它们的定义顺序来依次调用。
但是,你可以通过实现Ordered接口或使用@Order、@Priority注解来指定优先级。
6. 应用场景
BeanPostProcessor常被用于AOP(面向切面编程)的自动代理创建、日志记录、安全检查、性能监控等场景。
7. 注意事项
由于BeanPostProcessor能够影响所有bean的初始化过程,因此在使用时需要特别小心,避免引入不必要的复杂性或错误。
如果在postProcessBeforeInitialization或postProcessAfterInitialization方法中修改了bean的状态,需要确保这些修改是预期的,并且不会对其他bean或整个应用程序产生负面影响。
8. 总结
BeanPostProcessor是Spring框架中一个非常强大的工具,它允许开发者在bean的生命周期中的关键阶段插入自定义逻辑。然而,由于其强大的能力,使用时需要谨慎,并确保理解其工作原理和潜在影响。

现在写几个示例来看下是怎么执行的。

我这里定义A、B、C、D 、E、F类,分别如下:
A类

java 复制代码
package org.springframework.example.BPP;

import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

/**
 * 注解方式
 */
@Component
public class A implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		System.out.println("A.postProcessBeforeInitialization");
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		System.out.println("A.postProcessAfterInitialization");
		return bean;
	}
}

B类

java 复制代码
package org.springframework.example.BPP;

import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * 注解方式,加了顺序
 */
@Component
@Order(0)
public class B implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		System.out.println("B.postProcessBeforeInitialization, order: 0");
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		System.out.println("B.postProcessAfterInitialization, order: 0");
		return bean;
	}
}

C类

java 复制代码
package org.springframework.example.BPP;

import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

/**
 * 注解方式,实现Order
 */
@Component
public class C implements BeanPostProcessor, Ordered {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		System.out.println("C.postProcessBeforeInitialization, order: 1");
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		System.out.println("C.postProcessAfterInitialization, order: 1");
		return bean;
	}

	@Override
	public int getOrder() {
		return 1;
	}
}

D类

java 复制代码
package org.springframework.example.BPP;

import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.PriorityOrdered;
import org.springframework.stereotype.Component;

/**
 * 注解方式,实现PriorityOrdered
 */
@Component
public class D implements BeanPostProcessor, PriorityOrdered {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		System.out.println("D.postProcessBeforeInitialization, PriorityOrdered: 2");
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		System.out.println("D.postProcessAfterInitialization, PriorityOrdered: 2");
		return bean;
	}

	@Override
	public int getOrder() {
		return 2;
	}
}

E类

java 复制代码
package org.springframework.example.BPP;

import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.PriorityOrdered;
import org.springframework.stereotype.Component;

/**
 * 注解方式,实现PriorityOrdered
 */
@Component
public class E implements BeanPostProcessor, PriorityOrdered {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		System.out.println("E.postProcessBeforeInitialization, PriorityOrdered: 3");
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		System.out.println("E.postProcessAfterInitialization, PriorityOrdered: 3");
		return bean;
	}

	@Override
	public int getOrder() {
		return 3;
	}
}

F类

java 复制代码
package org.springframework.example.BPP;

import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

/**
 * 注解方式,实现Order
 */
@Component
public class F implements BeanPostProcessor, Ordered {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		System.out.println("F.postProcessBeforeInitialization, order: 4");
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		System.out.println("F.postProcessAfterInitialization, order: 4");
		return bean;
	}

	@Override
	public int getOrder() {
		return 4;
	}
}

BeanTest 测试类

java 复制代码
package org.springframework.example.BPP;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class BeanTest {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext =
				new AnnotationConfigApplicationContext("org.springframework.example.BPP");
	}
}

看下打印结果

text 复制代码
D.postProcessBeforeInitialization, PriorityOrdered: 2
E.postProcessBeforeInitialization, PriorityOrdered: 3
D.postProcessAfterInitialization, PriorityOrdered: 2
E.postProcessAfterInitialization, PriorityOrdered: 3
D.postProcessBeforeInitialization, PriorityOrdered: 2
E.postProcessBeforeInitialization, PriorityOrdered: 3
D.postProcessAfterInitialization, PriorityOrdered: 2
E.postProcessAfterInitialization, PriorityOrdered: 3
D.postProcessBeforeInitialization, PriorityOrdered: 2
E.postProcessBeforeInitialization, PriorityOrdered: 3
C.postProcessBeforeInitialization, order: 1
F.postProcessBeforeInitialization, order: 4
D.postProcessAfterInitialization, PriorityOrdered: 2
E.postProcessAfterInitialization, PriorityOrdered: 3
C.postProcessAfterInitialization, order: 1
F.postProcessAfterInitialization, order: 4
D.postProcessBeforeInitialization, PriorityOrdered: 2
E.postProcessBeforeInitialization, PriorityOrdered: 3
C.postProcessBeforeInitialization, order: 1
F.postProcessBeforeInitialization, order: 4
D.postProcessAfterInitialization, PriorityOrdered: 2
E.postProcessAfterInitialization, PriorityOrdered: 3
C.postProcessAfterInitialization, order: 1
F.postProcessAfterInitialization, order: 4

初步分析结果,后面再看原因:

1、打印的结果怎么是这样

2、AB为什么没有打印

3、PriorityOrdered 优先级高于Ordered

4、B类的@Order(0)好像没用

带着问题,来分析一下源码:

首先我们的BeanTest类里面的AnnotationConfigApplicationContext,new 的时候内部自带了refresh() ,在refresh()里面找到registerBeanPostProcessors(beanFactory),最后在PostProcessorRegistrationDelegate类的registerBeanPostProcessors中打个断点,后面调试用。

先整体分析一下这段代码:

java 复制代码
public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

		// WARNING: Although it may appear that the body of this method can be easily
		// refactored to avoid the use of multiple loops and multiple lists, the use
		// of multiple lists and multiple passes over the names of processors is
		// intentional. We must ensure that we honor the contracts for PriorityOrdered
		// and Ordered processors. Specifically, we must NOT cause processors to be
		// instantiated (via getBean() invocations) or registered in the ApplicationContext
		// in the wrong order.
		//
		// Before submitting a pull request (PR) to change this method, please review the
		// list of all declined PRs involving changes to PostProcessorRegistrationDelegate
		// to ensure that your proposal does not result in a breaking change:
		// https://github.com/spring-projects/spring-framework/issues?q=PostProcessorRegistrationDelegate+is%3Aclosed+label%3A%22status%3A+declined%22
		//上面的注释看,作者意思是这样写很多循环都是有意的,不需要重构
		//获取BeanPostProcessor的实现类的Bean名称集合
		//抛开Spring自带的BeanPostProcessor,这里将会获取到我们自定义的ABCDEF6个类,Spring 自带的BeanPostProcessor,后面再说
		String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

		// Register BeanPostProcessorChecker that logs an info message when
		// a bean is created during BeanPostProcessor instantiation, i.e. when
		// a bean is not eligible for getting processed by all BeanPostProcessors.
		//这里为什么要+1,我个人估计是因为BeanPostProcessorChecker本身也是一个BeanPostProcessor
		//BeanPostProcessorChecker 用来检测不符合BeanPostProcessors规则的Bean
		int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
		beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

		// Separate between BeanPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		//分别收集PriorityOrdered、Ordered和没有实现排序的BeanPostProcessor和MergedBeanDefinitionPostProcessor类型的Bean
		List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
			//查询指定名称的Bean 是否实现PriorityOrdered 接口,判断的代码也挺复杂,暂且不关心
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				//获取BeanPostProcessor的实例
				BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
				priorityOrderedPostProcessors.add(pp);
				//如果是MergedBeanDefinitionPostProcessor类型,该处理器后面再说
				if (pp instanceof MergedBeanDefinitionPostProcessor) {
					internalPostProcessors.add(pp);
				}
			}
			//如果实现了Ordered接口,则添加到orderedPostProcessorNames集合中
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			//如果没有实现排序接口,则添加到nonOrderedPostProcessorNames集合中
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		// First, register the BeanPostProcessors that implement PriorityOrdered.
		//先排序priorityOrderedPostProcessors
		//默认排序规则使用的OrderComparator,优先排序PriorityOrdered的实现类,顺序从小到大排序
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		//注册,就是往beanFactory中的一个List增加BeanPostProcessor
		//这里面又判断了beanFactory 是否是AbstractBeanFactory,关于什么事AbstractBeanFactory,也留着后面讲
		registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

		// Next, register the BeanPostProcessors that implement Ordered.
		//注册实现了Ordered的BeanPostProcessors
		List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String ppName : orderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			orderedPostProcessors.add(pp);
			//同样判断了MergedBeanDefinitionPostProcessor
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		//同理,排序
		sortPostProcessors(orderedPostProcessors, beanFactory);
		//同理,注册
		registerBeanPostProcessors(beanFactory, orderedPostProcessors);

		// Now, register all regular BeanPostProcessors.
		//处理没有实现排序的BeanPostProcessor
		List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String ppName : nonOrderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			nonOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		//同理,注册
		registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

		// Finally, re-register all internal BeanPostProcessors.
		//最后,处理MergedBeanDefinitionPostProcessor
		sortPostProcessors(internalPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, internalPostProcessors);

		// Re-register post-processor for detecting inner beans as ApplicationListeners,
		// moving it to the end of the processor chain (for picking up proxies etc).
		//添加ApplicationListenerDetector,其用来注册ApplicationListener类型的bean到上下文中,后面来测试一下
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
	}

下面来调试一下

解释第一个问题,打印结果解密,首先要知道在哪里调用postProcessBeforeInitialization和postProcessAfterInitialization。这里是在通过beanFactory.getBean 获取Bean的时候,没有Bean就会创建一个Bean,此时就会调用到,跟进去在AbstractAutowireCapableBeanFactory-->initializeBean 内部进行调用,此处打个断点调式。

由于几个内置BeanPostProcessor的存在,运行时会多次进入断点,所以我们都跳过,进入applyBeanPostProcessorsBeforeInitialization ,查看**getBeanPostProcessors()**的值,此时为几个内置BeanPostProcessor。

内置Bean自然没有我们的东西,跳过,后面的进入断点次数,不算内置BeanPostProcessor!!!

第二次进入断点,此时beanName 是 e

此时的getBeanPostProcessors() 还是原来的内置BeanPostProcessor,跳过。

第三次进入断点,此时beanName是"c"

这时getBeanPostProcessors() 多了D、E ,这时继续执行,将打印D、E的postProcessBeforeInitialization日志

继续往下执行到applyBeanPostProcessorsAfterInitialization,打印

到这里,Bean C已经处理完了,直接跳过,到下个断点

第四次进入断点是F

这里的getBeanPostProcessors() 还是DE,没有C,为什么?因为CF都是实现的Ordered,他们都是在一块处理,处理完后才添加到beanPostProcessors 中。由前面的代码分析可知。

所以在这里还是打印的DE的日志

第五次进入断点,beanName是a

这里开始打印DECF的日志

第六次进入断点,beanName是b

到这里所有的类都执行完了

解释一下第二个问题,AB为什么没有被打印。

从上面可知,AB 两个bean的创建在最后,后续没有其他Bean创建,因此没有执行AB 两个BeanPostProcessor的机会。要想打印,单独创建一个普通Bean,来测试一下。
G类

java 复制代码
package org.springframework.example.BPP;

import org.springframework.stereotype.Component;

@Component
public class G {
}

这里发现一个问题,B类的order 是0,怎么会在最后?实际是因为B类被认为是没有实现排序的BeanPostProcessor ,也就是 Order(0) 注解在这里没用!!!这也就回答了第四个问题。

解释第三个问题,PriorityOrdered 优先级高于Ordered ,因为代码是先处理的PriorityOrdered 的实现

最后对于大模型对BeanPostProcessor的介绍中的第五点

5. 排序和优先级
如果在Spring配置中定义了多个BeanPostProcessor,那么默认情况下,Spring容器会根据它们的定义顺序来依次调用。
但是,你可以通过实现Ordered接口或使用@Order、@Priority注解来指定优先级。

是错误的!!!目前只能通过实现Ordered或者PriorityOrdered接口

通过上面的实例测试@Order并没有起作用,@Priority 注解也没法在类上使用,查了一下该注解在javax.annotation-api中。

作者其他文章推荐:

基于Spring Boot 3.1.0 系列文章

  1. Spring Boot 源码阅读初始化环境搭建
  2. Spring Boot 框架整体启动流程详解
  3. Spring Boot 系统初始化器详解
  4. Spring Boot 监听器详解
  5. Spring Boot banner详解
  6. Spring Boot 属性配置解析
  7. Spring Boot 属性加载原理解析
  8. Spring Boot 异常报告器解析
  9. Spring Boot 3.x 自动配置详解
相关推荐
xlsw_2 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹3 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭4 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫4 小时前
泛型(2)
java
超爱吃士力架4 小时前
邀请逻辑
java·linux·后端
南宫生4 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石4 小时前
12/21java基础
java
李小白664 小时前
Spring MVC(上)
java·spring·mvc
GoodStudyAndDayDayUp5 小时前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea
装不满的克莱因瓶5 小时前
【Redis经典面试题六】Redis的持久化机制是怎样的?
java·数据库·redis·持久化·aof·rdb