【细读Spring Boot源码】Spring扩展点接口BeanPostProcessor-储备

BeanPostProcessor是Spring提供的一种扩展点,允许在Bean实例化和初始化前后插入自定义逻辑。接口包含两个方法postProcessBeforeInitialization和postProcessAfterInitialization,分别在初始化回调之前和之后调用。文章通过示例展示了如何在XML配置和SpringBoot中使用BeanPostProcessor,以及其对Bean生命周期的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

在读源码是必能看见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()


完~

求指点、关注、点赞

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

园长的牧歌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值