SpringBoot源码解读与原理分析(十二)后置处理器

3.6 后置处理器

3.6.1 后置处理器概述

SpringFramework的后置处理器有两种:

  • 针对bean对象的后置处理器:BeanPostProcessor
  • 针对BeanDefinition的后置处理器:BeanDefinitionRegistryPostProcessor

这两种都是针对IOC容器中的Bean,在其生命周期的某一阶段前后进行一些切入处理

  • BeanPostProcessor切入的时机是bean对象初始化阶段前、后。
  • BeanDefinitionRegistryPostProcessor切入的时机是在IOC容器的生命周期中,所有BeanDefinition都注册到BeanDefinitionRegistry后切入回调,它的主要工作是访问、修改已经存在的BeanDefinition。

另外,这两种都有一些扩展的子接口,它们切入的时机不尽相同,大致上如下图所示:

后置处理器在IOC容器与bean对象生命周期的切入时机
从上图可见,后置处理器在整个IOC容器以及bean对象的生命周期中有非常多可以切入的时机,因此IOC容器的可扩展性是非常强的。这个图非常重要,下文在梳理各接口的作用时,结合这个图一起看会更直观。

3.6.2 BeanPostProcessor

3.6.2.1 BeanPostProcessor概述

BeanPostProcessor是针对bean对象的后置处理器,其源码如下:

public interface BeanPostProcessor {

    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

}

分别来看BeanPostProcessor的两个方法,它们的javadoc很清楚地解释了其用处:

1.postProcessBeforeInitialization

Apply this BeanPostProcessorto the given new bean instance before any bean initialization callbacks (like InitializingBean’s afterPropertiesSetor a custom init-method). The bean will already be populated with property values. The returned bean instance may be a wrapper around the original. The default implementation returns the given beanas-is.

在任何bean的初始化回调(例如InitializingBean类的afterPropertiesSet方法,或者自定义的初始化方法)之前将此BeanPostProcessor应用于给定的新bean实例。给定的bean实例已经设置了属性值。返回的bean实例是原始bean实例的包装器。默认的实现会原样返回给定的bean实例。

2.postProcessAfterInitialization

Apply this BeanPostProcessorto the given new bean instance after any bean initialization callbacks (like InitializingBean’s afterPropertiesSetor a custom init-method). The bean will already be populated with property values. The returned bean instance may be a wrapper around the original.
In case of a FactoryBean, this callback will be invoked for both the FactoryBean instance and the objects created by the FactoryBean (as of Spring 2.0). The post-processor can decide whether to apply to either the FactoryBean or created objects or both through corresponding bean instanceof FactoryBeanchecks. This callback will also be invoked after a short-circuiting triggered by a InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiationmethod, in contrast to all other BeanPostProcessorcallbacks.
The default implementation returns the given beanas-is.

在任何bean的初始化回调(例如InitializingBean类的afterPropertiesSet方法,或者自定义的初始化方法)之后将此BeanPostProcessor应用于给定的新bean实例。给定的bean实例已经设置了属性值。返回的bean实例是原始bean实例的包装器。

对于FactoryBean,这个回调函数会被FactoryBean实例和FactoryBean创建的对象调用(截至Spring 2.0)。后置处理器可以通过相应的bean instanceof FactoryBean检查来决定是应用于FactoryBean实例还是FactoryBean创建的对象。这个回调函数也会在InstantiationAwareBeanPostProcessor类的postProcessBeforeInstantiation方法触发短路之后被调用,这与所有其他BeanPostProcessor回调函数不同。

默认的实现会原样返回给定的bean实例。

总结:postProcessBeforeInitialization在bean对象的初始化逻辑之前执行,postProcessAfterInitialization在初始化逻辑之后执行。另外postProcessAfterInitialization还可以对FactoryBean创建出的真实对象进行后置处理。

其切入时机如下图所示:

BeanPostProcessor的切入时机

3.6.2.2 BeanPostProcessor的扩展

借助IDEA得到BeanPostProcessor的扩展接口结构图:

BeanPostProcessor的扩展接口

1.InstantiationAwareBeanPostProcessor

这是一个支持实例化(Instantiation)的BeanPostProcessor,意味着它会干预bean对象的实例化阶段。

以下是该类的javadoc:

Subinterface of BeanPostProcessorthat adds a before-instantiation callback, and a callback after instantiation but before explicit properties are set or autowiring occurs.

第一段:BeanPostProcessor的子接口,添加了一个bean对象实例化前的回调函数,和一个实例化后的回调函数,但在显式属性设置或自动装配发生之前。

Typically used to suppress default instantiation for specific target beans, for example to create proxies with special TargetSources (pooling targets, lazily initializing targets, etc), or to implement additional injection strategies such as field injection.

第二段:通常用于抑制特定目标bean对象的默认实例化,例如创建具有特殊目标源(池化目标、延迟初始化目标等)的代理,或者实现额外的注入策略,如字段注入。

NOTE: This interface is a special purpose interface, mainly for internal use within the framework. It is recommended to implement the plain BeanPostProcessorinterface as far as possible, or to derive from InstantiationAwareBeanPostProcessorAdapterin order to be shielded from extensions to this interface.

第三段:此接口是一个特殊用途的接口,主要用于框架内部使用。建议尽可能实现普通的BeanPostProcessor接口,或者从InstantiationAwareBeanPostProcessorAdapter中派生出来,以便屏蔽对该接口的扩展。

总结:InstantiationAwareBeanPostProcessor会拦截并替换bean对象的默认实例化动作,也会拦截bean对象的属性注入和自动装配,并在此控制流程。

从源码上看,InstantiationAwareBeanPostProcessor在BeanPostProcessor的基础上,扩展了3个方法:

// 在目标bean对象实例化之前调用
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    return null;
}
// 在目标bean对象实例化之后调用
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
    return true;
}
// 在属性注入之前调用
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
    return null;
}

加入InstantiationAwareBeanPostProcessor后,Bean的初始化阶段如下图所示:

InstantiationAwareBeanPostProcessor的切入时机
至于这些切入的方法具体做了什么,会放到后面梳理生命周期的时候再展开。

2.DestructionAwareBeanPostProcessor

这是一个支持销毁(Destruction)的BeanPostProcessor,意味着它会干预bean对象的销毁阶段。

当IOC容器关闭时,会先销毁容器内所有单实例Bean,而销毁的过程中,除了回调bean对象本身定义的@PreDestroy注解标注的方法、destory-method等方法,还会回调所有DestructionAwareBeanPostProcessor类型的后置处理器。

以下是该类的javadoc:

Subinterface of BeanPostProcessorthat adds a before-destruction callback.
The typical usage will be to invoke custom destruction callbacks on specific bean types, matching corresponding initialization callbacks.

BeanPostProcessor的子接口,添加了一个销毁前的回调函数(postProcessBeforeDestruction方法)。典型的用法是在特定的bean类型调用自定义的销毁回调函数,以匹配相应的初始化回调。

总结:该后置处理器比较简单,会在ApplicationContext的close方法调用时执行。

3.MergedBeanDefinitionPostProcessor

这是一个支持合并Bean定义(MergedBeanDefinition)的BeanPostProcessor。

如果我们向IOC容器注册的Bean是一个有父类的派生类(即子类),那么SpringFramework在收集Bean中的信息时,不仅要收集当前类,还要收集它的父类,而负责收集父类的工作就交给MergedBeanDefinitionPostProcessor来完成。

以下是该类的javadoc:

Post-processor callback interface for merged bean definitions at runtime. BeanPostProcessorimplementations may implement this sub-interface in order to post-process the merged bean definition (a processed copy of the original bean definition) that the Spring BeanFactoryuses to create a bean instance.

第一段:在运行时合并Bean定义的后置处理器回调接口。BeanPostProcessor的实现可以实现这个子接口,以便对合并后的Bean定义(原始Bean定义的处理过的副本)进行后处理,BeanFactory用来创建bean实例。

The postProcessMergedBeanDefinitionmethod may for example introspect the bean definition in order to prepare some cached metadata before post-processing actual instances of a bean. It is also allowed to modify the bean definition but only for definition properties which are actually intended for concurrent modification. Essentially, this only applies to operations defined on the RootBeanDefinitionitself but not to the properties of its base classes.

第二段:例如,postProcessMergedBeanDefinition方法可以内省Bean定义,以便在后置处理Bean的实际实例之前准备一些缓存的元数据。它也允许修改Bean定义,但是只允许定义属性,这些属性实际上是用于并发修改的。本质上,这只适用于RootBeanDefinition本身定义的操作,而不适用于其基类的属性。

总结:MergedBeanDefinitionPostProcessor切入在bean对象的生命周期阶段中的属性赋值和自动注入之前,作用是提前收集好bean对象需要注入的属性(即元数据)。

MergedBeanDefinitionPostProcessor有一个非常重要的实现类AutowiredAnnotationBeanPostProcessor,它负责给bean对象实现基于注解的自动注入(@Autowired、@Inject、@Value等),而注入的依据是postProcessMergedBeanDefinition方法执行后整理的一组元素标记(checkedElements),后续的注入工作会根据这组打好的元素标记为bean对象依次注入属性值。

3.6.3 BeanFactoryPostProcessor

从类名可知,这是一个针对BeanFactory的后置处理器。

以下是该类的javadoc:

Factory hook that allows for custom modification of an application context’s bean definitions, adapting the bean property values of the context’s underlying bean factory.

第一段:这是一个工厂钩子,允许对应用程序上下文的Bean定义进行自定义修改,以调整上下文基础Bean工厂的bean对象属性值。

Useful for custom config files targeted at system administrators that override bean properties configured in the application context. See PropertyResourceConfigurerand its concrete implementations for out-of-the-box solutions that address such configuration needs.

第二段:对于针对系统管理员的定制配置文件非常有用,这些配置文件覆盖了应用程序上下文中配置的Bean属性。请参阅```PropertyResourceConfigurer``及其具体实现,以获得满足此类配置需求的开箱即用解决方案。

A BeanFactoryPostProcessormay interact with and modify bean definitions, but never bean instances. Doing so may cause premature bean instantiation, violating the container and causing unintended side-effects. If bean instance interaction is required, consider implementing BeanPostProcessorinstead.

第三段:BeanFactoryPostProcessor可以与Bean定义交互和修改,但不能与bean实例交互。这样做可能会导致bean过早实例化,破坏容器并导致意想不到的副作用。如果需要与bean实例交互,请考虑实现BeanPostProcessor。

Registration
An ApplicationContextauto-detects BeanFactoryPostProcessorbeans in its bean definitions and applies them before any other beans get created. A BeanFactoryPostProcessormay also be registered programmatically with a ConfigurableApplicationContext.

第四段:注册。ApplicationContext会在其Bean定义中自动检测BeanFactoryPostProcessor,并在创建任何其他bean之前应用它们。BeanFactoryPostProcessor也可以通过ConfigurableApplicationContext来编程注册。

Ordering
BeanFactoryPostProcessorbeans that are autodetected in an ApplicationContextwill be ordered according to org.springframework.core.PriorityOrderedand org.springframework.core.Orderedsemantics. In contrast, BeanFactoryPostProcessorbeans that are registered programmatically with a ConfigurableApplicationContextwill be applied in the order of registration; any ordering semantics expressed through implementing the PriorityOrderedor Orderedinterface will be ignored for programmatically registered post-processors. Furthermore, the @Orderannotation is not taken into account for BeanFactoryPostProcessorbeans.

第五段:排序。在ApplicationContext中自动检测的BeanFactoryPostProcessor,将根据org.springframework.core.PriorityOrdered和org.springframework.core. Ordered进行排序。相比之下,通过ConfigurableApplicationContext以编程方式注册的BeanFactoryPostProcessor将按照注册的顺序应用;任何通过实现PriorityOrdered或Ordered接口表达的排序语义都会被编程式注册的后置处理器忽略。此外,对于BeanFactoryPostProcessor来说,@Order注解没有被考虑在内。

总结:

  • 虽然类名带的是BeanFactory,但从文档可知该类操作的是Bean定义信息(BeanDefinition);
  • 可以在bean对象初始化之前修改Bean定义信息,最终影响到创建出来的bean对象;
  • 执行顺序根据PriorityOrdered和Ordered来确定;
  • 执行时机可以再回顾下本文开头给出的执行时机图:在加载BeanDefinition完成之后,初始化bean对象之前。

3.6.4 BeanDefinitionRegistryPostProcessor

从类名可知,这是一个针对Bean定义信息注册(BeanDefinitionRegistry)的后置处理器。

以下是该类的javadoc:

Extension to the standard BeanFactoryPostProcessorSPI, allowing for the registration of further bean definitions before regular BeanFactoryPostProcessor detection kicks in. In particular, BeanDefinitionRegistryPostProcessor may register further bean definitions which in turn define BeanFactoryPostProcessor instances.

它扩展到了标准的BeanFactoryPostProcessor SPI,允许在常规BeanFactoryPostProcessor检测生效之前注册更多的Bean定义。特别是,BeanDefinitionRegistryPostProcessor可以注册更多的Bean定义,这些定义又会定义BeanFactoryPostProcessor实例

总结:BeanDefinitionRegistryPostProcessor允许在BeanFactoryPostProcessor执行之前注册新的BeanDefinition,甚至注册新的BeanFactoryPostProcessor用于下一阶段的回调。

从设计上讲,BeanFactoryPostProcessor只用来修改、扩展BeanDefinition中的信息,而BeanDefinitionRegistryPostProcessor则可以在BeanFactoryPostProcessor处理BeanDefinition之前注册更多的BeanDefinition。

因此,BeanDefinitionRegistryPostProcessor的执行时机比BeanFactoryPostProcessor更早,我们可以再次回顾文章开头的执行时机图。

后置处理器在IOC容器与bean对象生命周期的切入时机

3.6.5 后置处理器对比

最后,简单对比下上面梳理的三种核心后置处理器。

BeanPostProcessorBeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor
处理目标bean对象BeanDefinitionBeanDefinition
执行时机bean对象的初始化阶段前、后(已创建的bean对象)BeanDefinition解析完毕并注册进BeanFactory之后(此时bean对象未实例化)配置文件、配置类已解析完毕并注册进BeanFactory,但还没有被BeanFactoryPostProcessor处理
可操作的空间给bean对象的属性赋值、创建代理对象等在BeanDefinition中增删属性、移除BeanDefinition等向BeanFactory注册新的BeanDefinition

分类专栏:SpringBoot源码解读与原理分析

  • 29
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

灰色孤星A

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

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

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

打赏作者

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

抵扣说明:

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

余额充值