前言
在读源码是必能看见BeanPostProcessor相关语句,这里收集记录下这个接口的作用和使用。
BeanPostProcessor一般称为Bean的后置处理器,它是Spring为我们提供的一个扩展点,可以在创建每个 Bean 的过程中进行干涉。详细点的说可以在 Bean 的实例化前后、Bean的初始化前后,使用我们自定义的逻辑。
接口分析
可以看见这个接口很简单,只有2个方法约束。
这两个方法有着相同的参数:
bean:实例化之后的bean对象
beanName:bean名称
// 在任何bean初始化回调 (例如InitializingBean的afterPropertiesSet或自定义init-method) 之前 ,
// 将此BeanPostProcessor应用于给定的新bean实例。bean将已经用属性值填充。返回的bean实例可能是围绕原始的包装器。
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
// 应用此Bean后处理器到给定的新bean实例之后任何bean初始化回调 (如InitializingBean的后属性集或自定义init-method)。
// bean将已经用属性值填充。返回的bean实例可能是围绕原始的包装器。
// 如果是FactoryBean,则将为FactoryBean实例和FactoryBean创建的对象调用此回调 (从Spring 2.0开始)。
// 后处理器可以通过相应的工厂的bean实例支票。
// 此回调也将在由
// InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation方法,与所有其他方法相比Bean后处理器回调。
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
这两个默认方法的方法名称只有点小区别,一个是Before,一个是After。还要注意Initialization
,意思是初始化,需要小心与Instantiation
实例化进行区分。
注意:接口中的两个方法是可以返回
null
。只是如果返回null
不会再执行后续的BeanPostProcessor
。
使用
通过使用来了解这个接口扩展的效果和如何生效的
基础准备
一个Person类
import lombok.Data;
@Data
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public Person(){}
}
一个User类
package com.ibi.cangcloud.settle.service.impl.test;
public class User {
}
一个实现BeanPostProcessor接口的MeBeanPostProcessor类
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* @author Wang WenLei
* @version 1.0
* @since 2023/5/5 10:32
*/
public class MeBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if("person".equals(beanName)){
System.out.println("初始化前====》" + "当前对象:" + bean + ",beanName = " + beanName);
// 先实例化为User
return new User();
}
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if("person".equals(beanName)){
System.out.println("初始化后====》" + "当前对象:" + bean + ",beanName = " + beanName);
// 再重新示例话为Person
return new Person("wwl");
}
return null;
}
}
Spring使用
创建一个xml文件在resources下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="wang.wenlei.service.impl.test.Person" id="person"></bean>
<bean class="wang.wenlei.service.impl.test.User" id="user"></bean>
</beans>
创建一个Main类包含main方法
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
/**
* @author Wang WenLei
* @version 1.0
* @since 2023/5/5 11:00
*/
public class Main {
public static void main(String[] args) {
ClassPathResource resource = new ClassPathResource("spring-config.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(resource);
// 这里使用的是BeanFactory容器,而不是使用的ApplicationContext
MeBeanPostProcessor meBeanPostProcessor = new MeBeanPostProcessor();
// BeanPostPorcessor是属于AbstractBeanFactory中一个List类型的属性,所以add进去。
factory.addBeanPostProcessor(meBeanPostProcessor);
Object person = factory.getBean("person");
Object user = factory.getBean("user");
System.out.println(person);
System.out.println(user);
}
}
打印效果
可以发现Bean名为person的对象先被实例化为User@7a8c8dcf,后又被实例化为Person。这样达到创建Bean的过程中进行干涉的效果
也可以看到Bean名为person实例化的User对象
与Bean名为user实例化的User对象
不一样
当然可以使用如下方法
在xml中添加
<bean class="wang.wenlei.service.impl.test.MeBeanPostProcessor" id="meBeanPostProcessor"></bean>
main函数改为如下方式
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml");
Object person = applicationContext.getBean("person");
Object user = applicationContext.getBean("user");
System.out.println(person);
System.out.println(user);
}
Springboot使用
把MeBeanPostProcessor 添加一个@Component
注解,并且把return改为 beanreturn bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
/**
* @author Wang WenLei
* @version 1.0
* @since 2023/5/5 10:32
*/
@Component
public class MeBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if("person".equals(beanName)){
System.out.println("初始化前====》" + "当前对象:" + bean + ",beanName = " + beanName);
return new User();
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if("person".equals(beanName)){
System.out.println("初始化后====》" + "当前对象:" + bean + ",beanName = " + beanName);
return new Person("wwl");
}
return bean;
}
}
在Springboot启动的main函数上加@ImportResource("classpath:spring-config.xml")
注解,引入XML
运行结果如下:
为什么把MeBeanPostProcessor上加一个@Component
注解就能让BeanPostProcessor生效?
refresh方法会调用 registerBeanPostProcessors()方法。这个方法会将检测到的 BeanPostProcessor 注入到SpringBoot容器AnnotationConfigApplicationContext中。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 省略一大部分代码
// 从BeanFactory扫描找出BeanPostProcessor,实例化并注册到BeanFactory里beanPostProcessors属性中
registerBeanPostProcessors(beanFactory);
}
// 省略
}
从模板方法看到详细调用
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// 这里使用了一个静态方法
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
看下registerBeanPostProcessors
源码中有一段WARNING,译文如下:
尽管看起来这个方法的主体很容易被重构,以避免使用多个循环和多个列表,但使用多个列表和多次传递处理器的名称是有意的。我们必须确保我们遵守 PriorityOrdered 和 Ordered 处理器的契约。具体来说,我们不能导致处理器被实例化(通过getBean()调用)或以错误的顺序在 ApplicationContext 中注册。在提交改变此方法的拉动请求(PR)之前,请查看所有涉及改变PostProcessorRegistrationDelegate的被拒绝的PR列表,以确保你的建议不会导致破坏性的改变:https://github.com/spring-projects/spring-framework/issues?q=PostProcessorRegistrationDelegate+is%3Aclosed+label%3A%22status%3A+declined%22
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名称
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.
// 重新计算BeanPostProcessor的数量
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
// 添加
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
// 根据不同的排序方式进行分类
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, register the BeanPostProcessors that implement PriorityOrdered.
// 注册PriorityOrdered类型的BeanPostProcessors
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
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);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// Now, register all regular BeanPostProcessors.
// 注册所有常规的BeanPostProcessors
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.
// 最后,再注册所有的内部BeanPostProcessors
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).
// 重新注册后处理器,以检测内部bean作为应用程序侦听器,将其移动到处理器链的末端 (用于拾取代理等)
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
看下实际的注册逻辑,实际上还是调用了factory.addBeanPostProcessor()方法
跟上面Spring的原理一样。
private static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
if (beanFactory instanceof AbstractBeanFactory) {
// Bulk addition is more efficient against our CopyOnWriteArrayList there
((AbstractBeanFactory) beanFactory).addBeanPostProcessors(postProcessors);
}
else {
for (BeanPostProcessor postProcessor : postProcessors) {
beanFactory.addBeanPostProcessor(postProcessor);
}
}
}
从原来的位置移除,在重新添加
this.beanPostProcessors
是BeanPostProcessorCacheAwareList的实例。
BeanPostProcessorCacheAwareList继承了CopyOnWriteArrayList
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
// Remove from old position, if any
this.beanPostProcessors.remove(beanPostProcessor);
// Add to end of list
this.beanPostProcessors.add(beanPostProcessor);
}
关于refresh更多,看【细读Spring Boot源码】重中之重refresh()
完~
求指点、关注、点赞