Spring BeanPostProcessor到底如何工作?


94

我正在研究Spring Core认证,我对Spring如何处理bean的生命周期,尤其是bean后处理器有疑问。

所以我有这个架构:

在此处输入图片说明

我很清楚这是什么意思:

在“ 装入Bean定义”阶段执行以下步骤:

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

  • Bean定义已添加到BeanFactory(每个索引均在其ID下进行索引)

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

然后,在Bean创建阶段执行以下步骤:

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

  • 依赖项注入后,每个bean都会进入后期处理阶段,在该阶段中可能会进行进一步的配置和初始化。

  • 在后期处理之后,bean被完全初始化并可以使用(通过其id进行跟踪,直到上下文被销毁)

好的,这对我来说很清楚,我也知道有两种类型的Bean后处理器

  • 初始化程序:如果有指示,则初始化Bean(即@PostConstruct)。

  • 所有其余的:其允许额外的配置和其之前或初始化步骤之后运行

我张贴这张幻灯片:

在此处输入图片说明

所以对我来说很清楚初始化器 bean后处理器是什么(它们是用@PostContruct注释注释的方法,这些方法在setter方法之后立即自动调用(因此在依赖项注入之后),我知道我可以使用执行一些初始化批处理(如上例中那样填充缓存)。

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

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

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

我可以很容易地想到为什么我需要一个@PostContruct带注释的方法,但是我无法弄清楚另一种bean后处理器的典型示例,您能告诉我一些什么时候使用的典型示例吗?


我很确定您不应该共享幻灯片的图像:)
Reg

@Reg这些图像来自什么确切的课程/演示?
Malvon

@Malvon这是上一版的Pivotal春季官方核心课程的内容。和顺便说一句-如果你正在准备考试,忽略了与XML :)什么
注册

@Reg是否可以在不实际参加培训课程的情况下购买课程?
马尔文(Malvon)

我想知道图表“后期处理Bean定义”的紫色部分会发生什么?
Akshay Hiremath

Answers:


48

Spring doc在使用BeanPostProcessor定制bean下解释了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的生命周期,以及何时确切调用该方法,请检查文档

postProcessBeforeInitialization(Object bean,String beanName)在任何bean初始化回调(如InitializingBean的afterPropertiesSet或自定义init-method)之前,将此BeanPostProcessor应用于给定的新bean实例。

postProcessAfterInitialization(Object bean,String beanName)在任何bean初始化回调(如InitializingBean的afterPropertiesSet或自定义的init-method)之后,将此BeanPostProcessor应用于给定的新bean实例。

重要的一点是

该bean将已经用属性值填充。

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

您可以配置多个BeanPostProcessor实例,并且可以通过设置order属性来控制这些BeanPostProcessor的执行顺序。


30

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

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


6
真实示例的荣誉!
突袭

感谢您提供实际用例,而不仅仅是理论
Amol Aggarwal

4

区别在于BeanPostProcessor将对所有定义的bean进行上下文初始化然后调用postProcessBeforeInitializationpostProcessAfterInitialization

但是@PostConstruct仅用于要在构造函数或set方法之后自定义bean创建的特定类。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.