Spring 执行顺序:PostProcessor 接口

回目录

代码:https://gitee.com/free/boot-order/tree/master/src/main/java/com/github/abel533/postprocessor

PostProcessor 类接口如下所示:

在这里插入图片描述

其中 BeanPostProcessor 是最常见的一个系列,BeanFactoryPostProcessor 和 EnvironmentPostProcessor 不常用。

由于上图所示的继承关系和不同 PostProcessor 使用的要求限制,这里不能同时使用所有这些 PostProcessor,所以下面是针对不同情况去测试方法的执行顺序。

因为 BeanFactoryPostProcessor 没有使用限制,所以后续所有例子中都会实现该接口,而且该接口都是第一个调用的。

BeanPostProcessor 系列

用途:允许修改新的 bean 实例的工厂钩子函数,例如检查标记接口或者用代理包装 bean。
通常在 postProcessBeforeInitialization 方法中处理标记接口,在 postProcessAfterInitialization 中处理代理 beans。
该方法会对上下文中的所有 bean 进行处理,因此根据 bean 的数量,会执行多次,所以后续日志中都会频繁出现调用的日志。

在 4 个子接口中,都针对 BeanPostProcessor 增加了额外的处理方法,额外的方法都是在

BeanPostProcessor 接口

src\main\java\com\github\abel533\postprocessor\base

由于执行多次的原因,下面贴出部分执行顺序:

  1. BeanFactoryPostProcessor#postProcessBeanFactory
  2. BeanPostProcessor#postProcessBeforeInitialization - org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
  3. BeanPostProcessor#postProcessBeforeInitialization - org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
  4. BeanPostProcessor#postProcessAfterInitialization - org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
  5. BeanPostProcessor#postProcessBeforeInitialization - transactionAttributeSource
  6. BeanPostProcessor#postProcessAfterInitialization - transactionAttributeSource
  7. BeanPostProcessor#postProcessBeforeInitialization - transactionInterceptor
  8. BeanPostProcessor#postProcessAfterInitialization - transactionInterceptor
  9. BeanPostProcessor#postProcessBeforeInitialization - org.springframework.transaction.config.internalTransactionAdvisor
  10. BeanPostProcessor#postProcessAfterInitialization - org.springframework.transaction.config.internalTransactionAdvisor
  11. BeanPostProcessor#postProcessAfterInitialization - org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat

AbstractApplicationContext#refresh 中可以看到 PostProcessor 的执行顺序,代码如下(有删减):

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        try {
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);

            // 执行 0
            // Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);

            // 注册所有 BeanPostProcessors,这里会区分是否继承了 PriorityOrdered 和 Ordered
            // 执行的优先级按照 PriorityOrdered > Ordered > 无
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            initMessageSource();

            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();

            // 执行 1~end
            // Initialize other special beans in specific context subclasses.
            onRefresh();
        }
    }
}

1~10 具体在 AbstractAutowireCapableBeanFactory#initializeBean 初始化 Bean 的时候,先调用了 postProcessBeforeInitialization 方法,然后是 Bean 的初始化方法,随后就是 postProcessAfterInitialization 方法,代码如下(有删减):。

	protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (mbd == null || !mbd.isSynthetic()) {
		    // postProcessBeforeInitialization 方法
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}
		try {
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
		}
		if (mbd == null || !mbd.isSynthetic()) {
		    // postProcessAfterInitialization 方法
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

上述执行顺序中,执行 1 的时候处理的 org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat,在之后的 postProcessAfterInitialization 方法中,由于获取 advisor 进行代理,又进入了其他 bean 的 PostProcessor 方法,直到 10 的时候,才返回到 1 对应的 bean 上。

SmartInstantiationAwareBeanPostProcessor

SmartInstantiationAwareBeanPostProcessor 继承了 InstantiationAwareBeanPostProcessor,这俩接口都是用于 Spring 框架内部使用的接口,接口方法可以根据需要随时添加(不对外兼容)不推荐使用,
如果要使用,可以使用 InstantiationAwareBeanPostProcessorAdapter 类,该类会保证所有默认方法实现的正确性。

下面以 InstantiationAwareBeanPostProcessorAdapter 为例查看执行顺序。

为了能完整的测试所有的接口方法,特别实现了下面两个循环依赖的类:

public class User {
    @Autowired
    private UserExt ext;
    private String id;

    public User() {
    }
    //其他
}

public class UserExt {
    @Autowired
    private User user;
    private String name;

    public UserExt() {
    }
    //其他
}

由于所有 Bean 都会触发接口输出日志,因此在日志中过滤只显示了其中 3 个 bean 的日志,执行顺序如下:

  1. InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation - org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
  2. SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors - org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
  3. InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation - org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
  4. InstantiationAwareBeanPostProcessor#postProcessProperties - org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
  5. BeanPostProcessor#postProcessBeforeInitialization - org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
  6. BeanPostProcessor#postProcessAfterInitialization - org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
  7. InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation - user
  8. InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation - user
  9. InstantiationAwareBeanPostProcessor#postProcessProperties - user
  10. InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation - userExt
  11. InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation - userExt
  12. InstantiationAwareBeanPostProcessor#postProcessProperties - userExt
  13. SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference - user
  14. BeanPostProcessor#postProcessBeforeInitialization - userExt
  15. BeanPostProcessor#postProcessAfterInitialization - userExt
  16. BeanPostProcessor#postProcessBeforeInitialization - user
  17. BeanPostProcessor#postProcessAfterInitialization - user

SmartInstantiationAwareBeanPostProcessor#predictBeanType 执行很频繁,从顺序中去掉

不存在依赖的前提下,就是按照 ServletWebServerFactoryConfiguration$EmbeddedTomcat 的顺序执行的,摘抄如下:

  1. InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
    在实例化目标bean之前应用此BeanPostProcessor。
  2. SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors
    确定要用于给定bean的候选构造函数。
  3. InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
    在bean实例化之后,通过构造函数或工厂方法,但在Spring属性填充(来自显式属性或自动装配)之前执行操作。
  4. InstantiationAwareBeanPostProcessor#postProcessProperties
    在工厂将它们应用于给定bean之前对给定属性值进行后处理,不需要属性描述符。
  5. BeanPostProcessor#postProcessBeforeInitialization
    在任何bean初始化回调(如InitializingBean afterPropertiesSet 或自定义init方法)之前,将此BeanPostProcessor应用于给定的新bean实例。
  6. BeanPostProcessor#postProcessAfterInitialization
    在任何bean初始化回调(如InitializingBean afterPropertiesSet 或自定义init方法)之后,将此BeanPostProcessor应用于给定的新bean实例。

接下来看看 User 和 UserExt 两个循环依赖 bean 的创建过程。

  1. InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation - user
    在实例化目标bean之前应用此BeanPostProcessor。
  2. InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation - user
    在bean实例化之后,通过构造函数或工厂方法,但在Spring属性填充(来自显式属性或自动装配)之前执行操作。
  3. InstantiationAwareBeanPostProcessor#postProcessProperties - user
    在工厂将它们应用于给定bean之前对给定属性值进行后处理,不需要属性描述符。
  4. InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation - userExt
    在实例化目标bean之前应用此BeanPostProcessor。
  5. InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation - userExt
    在bean实例化之后,通过构造函数或工厂方法,但在Spring属性填充(来自显式属性或自动装配)之前执行操作。
  6. InstantiationAwareBeanPostProcessor#postProcessProperties - userExt
    在工厂将它们应用于给定bean之前对给定属性值进行后处理,不需要属性描述符。
  7. SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference - user
    获取早期访问指定bean的引用,通常用于解析循环引用。
  8. BeanPostProcessor#postProcessBeforeInitialization - userExt
    在任何bean初始化回调(如InitializingBean afterPropertiesSet 或自定义init方法)之前,将此BeanPostProcessor应用于给定的新bean实例。
  9. BeanPostProcessor#postProcessAfterInitialization - userExt
    在任何bean初始化回调(如InitializingBean afterPropertiesSet 或自定义init方法)之后,将此BeanPostProcessor应用于给定的新bean实例。
  10. BeanPostProcessor#postProcessBeforeInitialization - user
    在任何bean初始化回调(如InitializingBean afterPropertiesSet 或自定义init方法)之前,将此BeanPostProcessor应用于给定的新bean实例。
  11. BeanPostProcessor#postProcessAfterInitialization - user
    在任何bean初始化回调(如InitializingBean afterPropertiesSet 或自定义init方法)之后,将此BeanPostProcessor应用于给定的新bean实例。

从这儿的逻辑看到,初始化 User 的时候,由于需要注入 UserExt,就去初始化 UserExt 了,由于 UserExt 中也需要 User,并且 User 已经有了早期的 bean 引用,因此 UserExt 初始化完成,此后返回 User 的初始化过程,至此两个 bean 创建成功。

这里的示例中,都是通过属性注入的,因此可以成功。如果 User 使用构造参数注入 UserExt,由于这里扫描顺序 User 更早,就无法解决这个循环依赖,会报错如下:

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

┌─────┐
|  user defined in class path resource [com/github/abel533/postprocessor/instantiation/CircleConfig.class]
↑     ↓
|  userExt (field private com.github.abel533.postprocessor.instantiation.User com.github.abel533.postprocessor.instantiation.UserExt.user)
└─────┘

但是如果调整这两个 Bean 的顺序(在 CircleConfig 中),就会成功。由于初始化顺序的不确定性,构造参数方式很难解决循环依赖,所以存在循环依赖的情况时,使用属性或方法方式注入。

EnvironmentPostProcessor

这是 Spring Boot 特有的接口,会在刷新应用程序上下文之前调用。支持通过 Ordered 接口进行排序。

必须在 META-INF/spring.factories 使用此类的完全限定名称作为键来注册 EnvironmentPostProcessor 实现 。

例如本例:

org.springframework.boot.env.EnvironmentPostProcessor=com.github.abel533.postprocessor.environment.EnvironmentPostProcessorImpl

由于这个配置会影响其他测试的执行顺序(EnvironmentPostProcessor 肯定是第一个),所以本项目中注释了上述配置。

该接口比所有其他 PostProcessor 执行的都早,由于接口特殊,这里不再继续往下进行分析。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

isea533

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

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

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

打赏作者

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

抵扣说明:

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

余额充值