文章目录
3.6 后置处理器
3.6.1 后置处理器概述
SpringFramework的后置处理器有两种:
- 针对bean对象的后置处理器:BeanPostProcessor
- 针对BeanDefinition的后置处理器:BeanDefinitionRegistryPostProcessor
这两种都是针对IOC容器中的Bean,在其生命周期的某一阶段前后进行一些切入处理。
- BeanPostProcessor切入的时机是bean对象初始化阶段前、后。
- BeanDefinitionRegistryPostProcessor切入的时机是在IOC容器的生命周期中,所有BeanDefinition都注册到BeanDefinitionRegistry后切入回调,它的主要工作是访问、修改已经存在的BeanDefinition。
另外,这两种都有一些扩展的子接口,它们切入的时机不尽相同,大致上如下图所示:
从上图可见,后置处理器在整个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
BeanPostProcessor
to the given new bean instance before any bean initialization callbacks (like InitializingBean’safterPropertiesSet
or 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 givenbean
as-is.
在任何bean的初始化回调(例如InitializingBean类的afterPropertiesSet方法,或者自定义的初始化方法)之前将此BeanPostProcessor应用于给定的新bean实例。给定的bean实例已经设置了属性值。返回的bean实例是原始bean实例的包装器。默认的实现会原样返回给定的bean实例。
2.postProcessAfterInitialization
Apply this
BeanPostProcessor
to the given new bean instance after any bean initialization callbacks (like InitializingBean’safterPropertiesSet
or 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 correspondingbean instanceof FactoryBean
checks. This callback will also be invoked after a short-circuiting triggered by aInstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
method, in contrast to all otherBeanPostProcessor
callbacks.
The default implementation returns the givenbean
as-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创建出的真实对象进行后置处理。
其切入时机如下图所示:
3.6.2.2 BeanPostProcessor的扩展
借助IDEA得到BeanPostProcessor的扩展接口结构图:
1.InstantiationAwareBeanPostProcessor
这是一个支持实例化(Instantiation)的BeanPostProcessor,意味着它会干预bean对象的实例化阶段。
以下是该类的javadoc:
Subinterface of
BeanPostProcessor
that 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
BeanPostProcessor
interface as far as possible, or to derive fromInstantiationAwareBeanPostProcessorAdapter
in 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的初始化阶段如下图所示:
至于这些切入的方法具体做了什么,会放到后面梳理生命周期的时候再展开。
2.DestructionAwareBeanPostProcessor
这是一个支持销毁(Destruction)的BeanPostProcessor,意味着它会干预bean对象的销毁阶段。
当IOC容器关闭时,会先销毁容器内所有单实例Bean,而销毁的过程中,除了回调bean对象本身定义的@PreDestroy注解标注的方法、destory-method等方法,还会回调所有DestructionAwareBeanPostProcessor类型的后置处理器。
以下是该类的javadoc:
Subinterface of
BeanPostProcessor
that 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.
BeanPostProcessor
implementations may implement this sub-interface in order to post-process the merged bean definition (a processed copy of the original bean definition) that the SpringBeanFactory
uses to create a bean instance.
第一段:在运行时合并Bean定义的后置处理器回调接口。BeanPostProcessor的实现可以实现这个子接口,以便对合并后的Bean定义(原始Bean定义的处理过的副本)进行后处理,BeanFactory用来创建bean实例。
The
postProcessMergedBeanDefinition
method 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 theRootBeanDefinition
itself 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
PropertyResourceConfigurer
and its concrete implementations for out-of-the-box solutions that address such configuration needs.
第二段:对于针对系统管理员的定制配置文件非常有用,这些配置文件覆盖了应用程序上下文中配置的Bean属性。请参阅```PropertyResourceConfigurer``及其具体实现,以获得满足此类配置需求的开箱即用解决方案。
A
BeanFactoryPostProcessor
may 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 implementingBeanPostProcessor
instead.
第三段:BeanFactoryPostProcessor可以与Bean定义交互和修改,但不能与bean实例交互。这样做可能会导致bean过早实例化,破坏容器并导致意想不到的副作用。如果需要与bean实例交互,请考虑实现BeanPostProcessor。
Registration
AnApplicationContext
auto-detectsBeanFactoryPostProcessor
beans in its bean definitions and applies them before any other beans get created. ABeanFactoryPostProcessor
may also be registered programmatically with aConfigurableApplicationContext
.
第四段:注册。ApplicationContext会在其Bean定义中自动检测BeanFactoryPostProcessor,并在创建任何其他bean之前应用它们。BeanFactoryPostProcessor也可以通过ConfigurableApplicationContext来编程注册。
Ordering
BeanFactoryPostProcessor
beans that are autodetected in anApplicationContext
will be ordered according toorg.springframework.core.PriorityOrdered
andorg.springframework.core.Ordered
semantics. In contrast,BeanFactoryPostProcessor
beans that are registered programmatically with aConfigurableApplicationContext
will be applied in the order of registration; any ordering semantics expressed through implementing thePriorityOrdered
orOrdered
interface will be ignored for programmatically registered post-processors. Furthermore, the@Order
annotation is not taken into account forBeanFactoryPostProcessor
beans.
第五段:排序。在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
BeanFactoryPostProcessor
SPI, 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更早,我们可以再次回顾文章开头的执行时机图。
3.6.5 后置处理器对比
最后,简单对比下上面梳理的三种核心后置处理器。
BeanPostProcessor | BeanFactoryPostProcessor | BeanDefinitionRegistryPostProcessor | |
---|---|---|---|
处理目标 | bean对象 | BeanDefinition | BeanDefinition |
执行时机 | bean对象的初始化阶段前、后(已创建的bean对象) | BeanDefinition解析完毕并注册进BeanFactory之后(此时bean对象未实例化) | 配置文件、配置类已解析完毕并注册进BeanFactory,但还没有被BeanFactoryPostProcessor处理 |
可操作的空间 | 给bean对象的属性赋值、创建代理对象等 | 在BeanDefinition中增删属性、移除BeanDefinition等 | 向BeanFactory注册新的BeanDefinition |
分类专栏:SpringBoot源码解读与原理分析