Spring BeanPostProcessor 究竟是如何工作的?

Posted

技术标签:

【中文标题】Spring BeanPostProcessor 究竟是如何工作的?【英文标题】:How exactly does the Spring BeanPostProcessor work? 【发布时间】:2015-06-26 21:49:00 【问题描述】:

我正在学习 Spring Core 认证,我对 Spring 如何处理 bean 生命周期,尤其是 bean 后处理器有一些疑问。

所以我有这个架构:

我很清楚这意味着什么:

以下步骤发生在加载 Bean 定义阶段:

@Configuration 类被处理和/或 @Components 被处理 扫描和/或 XML 文件被解析。

添加到 BeanFactory 的 Bean 定义(每个都在其 id 下编制索引)

调用特殊的BeanFactoryPostProcessor bean,它可以修改任何bean的定义(例如用于属性占位符值的替换)。

然后在beans创建阶段进行以下步骤:

默认情况下,每个 bean 都被急切地实例化(以正确的顺序创建并注入其依赖项)。

依赖注入后,每个 bean 都会经过一个后处理 可能发生进一步配置和初始化的阶段。

在后处理之后,bean 完全初始化并准备好使用(由其 id 跟踪,直到上下文被销毁)

好的,这对我来说很清楚,我也知道 有两种类型的 bean 后处理器,它们是:

Initializers:根据指示初始化 bean(即@PostConstruct)。

所有其余部分:允许进行额外配置并且可以在初始化步骤之前或之后运行

我张贴这张幻灯片:

所以我很清楚 initializers bean 后处理器有什么作用(它们是带有 @PostContruct 注释的方法,并且在 setter 之后立即自动调用方法(所以在依赖注入之后),并且我知道我可以使用它来执行一些初始化批处理(如在前面的示例中填充缓存)。

但究竟什么代表了另一个 bean 后处理器?当我们说这些步骤在初始化阶段之前或之后执行时,我们的意思是什么?

所以我的 bean 被实例化并注入了它的依赖项,因此初始化阶段完成(通过执行 @PostContruct 注释方法)。在初始化阶段之前使用 Bean 后处理器是什么意思?这意味着它发生在 @PostContruct 注释方法执行之前?这是否意味着它可能发生在依赖注入之前(在调用setter方法之前)?

当我们说它在初始化步骤之后执行时,我们的确切意思是什么。这意味着它发生在执行 @PostContruct 注释方法之后,还是什么?

我很容易想到为什么我需要一个 @PostContruct 带注释的方法,但我想不出另一种 bean 后处理器的典型例子,你能给我一些典型的例子吗什么时候用的?

【问题讨论】:

我很确定你不应该分享幻灯片的图片 :) @Reg 这些图片来自什么确切的课程/演示文稿? @Malvon 这是上一期 Pivotal 官方 Spring 核心课程的内容。顺便说一句 - 如果您正在准备考试,请忽略 XML 的任何内容 :) @Reg 有没有办法在不参加培训课程的情况下购买课程? 我想知道“后处理 Bean 定义”图表的紫色部分会发生什么? 【参考方案1】:

不同之处在于BeanPostProcessor 将挂钩上下文初始化,然后为所有已定义的bean 调用postProcessBeforeInitializationpostProcessAfterInitialization

但是@PostConstruct只是用于你想在构造函数或set方法之后自定义bean创建的具体类。

【讨论】:

【参考方案2】:

bean 后处理器的典型示例是当您想将原始 bean 包装在代理实例中时,例如使用@Transactional 注解时。

bean 后处理器将收到 bean 的原始实例,它可以调用目标上的任何方法,但它也会返回应该绑定在应用程序上下文中的实际 bean 实例,这意味着它可以实际上返回它想要的任何对象。这很有用的典型场景是 bean 后处理器将目标包装在代理实例中。绑定在应用程序上下文中的 bean 上的所有调用都将通过代理,然后代理在目标 bean 调用之前和/或之后执行一些魔法,例如AOP 或事务管理。

【讨论】:

感谢一个真实的例子! 感谢您提供实际用例,而不仅仅是理论【参考方案3】:

Spring 文档解释了Customizing beans using BeanPostProcessor 下的 BPP。 BPP bean 是一种特殊的 bean,它在任何其他 bean 之前创建并与新创建的 bean 交互。有了这个结构,Spring 为您提供了连接和自定义生命周期行为的方法,只需自己实现 BeanPostProcessor

拥有像这样的自定义 BPP

public class CustomBeanPostProcessor implements BeanPostProcessor 

    public CustomBeanPostProcessor() 
        System.out.println("0. Spring calls constructor");
    

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException 
        System.out.println(bean.getClass() + "  " + beanName);
        return bean;
    

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException 
        System.out.println(bean.getClass() + "  " + beanName);
        return bean;
    

将被调用并打印出每个创建的 bean 的类和 bean 名称。

要了解该方法如何适应 bean 的生命周期,以及该方法何时被调用,请查看 docs

postProcessBeforeInitialization(Object bean, String beanName) 应用 这个 BeanPostProcessor 在任何 bean 之前到给定的新 bean 实例 初始化回调(如 InitializingBean 的 afterPropertiesSet 或自定义初始化方法)。

postProcessAfterInitialization(Object bean, String beanName) 应用 这个 BeanPostProcessor 在任何 bean 之后到给定的新 bean 实例 初始化回调(如 InitializingBean 的 afterPropertiesSet 或自定义初始化方法)。

还有一点很重要

bean 将已填充属性值。

对于与@PostConstruct 的关系,请注意,此注解是声明postProcessAfterInitialization 方法的便捷方式,当您通过注册CommonAnnotationBeanPostProcessor 或在中指定<context:annotation-config /> 时,Spring 会意识到这一点豆配置文件。 @PostConstruct 方法是在任何其他 postProcessAfterInitialization 之前还是之后执行取决于 order 属性

你可以配置多个 BeanPostProcessor 实例,你可以 通过设置来控制这些 BeanPostProcessor 的执行顺序 订单属性。

【讨论】:

您确定@PostConstruct 相对于其他BPP afterInitialziation 的顺序吗?我尝试让 BPP 实现 PriorityOrdered 并返回 HIGHEST_PRECEDENCE,但仍然在它之前运行 @PostConstruct 注释方法。它还在 init() 和 InitializingBean 的 afterPropertiesSet() 之前运行。

以上是关于Spring BeanPostProcessor 究竟是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章

Ioc容器-BeanPostProcessor-Spring 源码

spring源码之BeanPostProcessor

Spring 的 BeanPostProcessor接口实现

Spring点滴五:Spring中的后置处理器BeanPostProcessor讲解

Spring源码解析之BeanPostProcessor

Spring中的后置处理器BeanPostProcessor讲解