优秀的编程知识分享平台

网站首页 > 技术文章 正文

springboot学习三:Spring BeanPostProcessor钩子

nanyue 2024-08-03 17:40:23 技术文章 7 ℃

本章目的

认识SpringBPP,掌握BeanPostProcessor。

本章可能会有些枯燥,客官可以直接看最下面的总结。

系统版本

  1. jdk1.8
  2. springboot 2.1.6.RELEASE
  3. 开发工具(IntelliJ IDEA 2018.1.5 x64)
  4. apache maven(3.6.0,本章采用maven形式管理jar包,具体配置环境变量以及使用请自行查找资料)

开始。。。

在spring世界中,当我们要对bean的实例化,初始化过程中做点什么的时候,作为开发人员,显然不需要继承ApplicationContext或者BeanFactory,这个时候,bpp提供对外的钩子,就被派上用场了。下面我们介绍几个比较常见的bpp接口。

1. BeanFactoryPostProcessor

@FunctionalInterface
public interface BeanFactoryPostProcessor {
 /**
 * Modify the application context's internal bean factory after its standard
 * initialization. All bean definitions will have been loaded, but no beans
 * will have been instantiated yet. This allows for overriding or adding
 * properties even to eager-initializing beans.
 * @param beanFactory the bean factory used by the application context
 * @throws org.springframework.beans.BeansException in case of errors
 */
 void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

实现该接口,可以在spring的bean创建之前,修改bean的定义属性。也就是说,Spring允许BeanFactoryPostProcessor在容器实例化任何其它bean之前读取配置元数据,并可以根据需要进行修改,例如可以把bean的scope从singleton改为prototype,也可以把property的值给修改掉。可以同时配置多个BeanFactoryPostProcessor,并通过设置’order’属性来控制各个BeanFactoryPostProcessor的执行次序。

注意:BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的。接口方法的入参是ConfigurrableListableBeanFactory,使用该参数,可以获取到相关bean的定义信息

spring中,有内置的一些BeanFactoryPostProcessor实现类,常用的有:

  • org.springframework.beans.factory.config.PropertyPlaceholderConfigurer:${}属性覆盖
  • org.springframework.beans.factory.config.PropertyOverrideConfigurer
  • org.springframework.beans.factory.config.CustomEditorConfigurer:用来注册自定义的属性编辑器

2. BeanPostProcessor :bean的后置处理器

public interface BeanPostProcessor {
 /**
 * Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean
 * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
 * 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.
 * <p>The default implementation returns the given {@code bean} as-is.
 * @param bean the new bean instance
 * @param beanName the name of the bean
 * @return the bean instance to use, either the original or a wrapped one;
 * if {@code null}, no subsequent BeanPostProcessors will be invoked
 * @throws org.springframework.beans.BeansException in case of errors
 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
 */
 @Nullable
 default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
 return bean;
 }
 /**
 * Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean
 * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
 * 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.
 * <p>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 {@code bean instanceof FactoryBean} checks.
 * <p>This callback will also be invoked after a short-circuiting triggered by a
 * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
 * in contrast to all other BeanPostProcessor callbacks.
 * <p>The default implementation returns the given {@code bean} as-is.
 * @param bean the new bean instance
 * @param beanName the name of the bean
 * @return the bean instance to use, either the original or a wrapped one;
 * if {@code null}, no subsequent BeanPostProcessors will be invoked
 * @throws org.springframework.beans.BeansException in case of errors
 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
 * @see org.springframework.beans.factory.FactoryBean
 */
 @Nullable
 default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
 return bean;
 }

BeanPostProcessor,可以在spring容器实例化bean之后,在执行bean的初始化方法前后,添加一些自己的处理逻辑。这里说的初始化方法,指的是下面两种:

  1. bean实现了InitializingBean接口,对应的方法为afterPropertiesSet
  2. 在bean定义的时候,通过init-method设置的方法

注意:BeanPostProcessor是在spring容器加载了bean的定义文件并且实例化bean之后执行的。BeanPostProcessor的执行顺序是在BeanFactoryPostProcessor之后。 postProcessBeforeInitialization 是在bean实例化之前,属性设置之后但是初始化之前

pstProcessAfterInitialization是在所有初始化方法之后

这个接口很重要,所以 接下来,我们重点介绍下这个接口。先看下 他的继承关系。

继承实现关系

从图中可以看出,BeanPostProcessor的实现类有很多,我们从左向右挑几个比较常用的:1). DestructionAwareBeanPostProcessor :销毁Bean后置处理器

public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {
 /**
 * Apply this BeanPostProcessor to the given bean instance before its
 * destruction, e.g. invoking custom destruction callbacks.
 ...
 */
 void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;
 /**
 * Determine whether the given bean instance requires destruction by this
 * post-processor.
 * <p>The default implementation returns {@code true}. 
 ...
 */
 default boolean requiresDestruction(Object bean) {
 return true;
 }
}
注释已经很清楚了,就是销毁bean之前,你还想做什么。

2). MergedBeanDefinitionPostProcessor :合并Bean定义后置处理器

public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {
 /**
 * Post-process the given merged bean definition for the specified bean.
 ...
 */
 void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);
 /**
 * A notification that the bean definition for the specified name has been reset,
 * and that this post-processor should clear any metadata for the affected bean.
 ...
 */
 default void resetBeanDefinition(String beanName) {
 }
}

合并Bean定义后置处理器,感觉 概念很模糊。大家可以看下,它的一个实现类AutuwiredAnnotationBeanPostProcessor

 //在每个bean实例化后,初始化前执行,获取并记录该bean属性注入的元数据(成员),在随后的属性注入时使用
 @Override
 public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
 InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
 metadata.checkConfigMembers(beanDefinition);
 }

这个方法,检查并注册需要注入的成员,然后调用InstantiationAwareBeanPostProcessor#postProcessProperties方法,完成所有成员的属性注入(依赖注入)

 @Override
 public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
 InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
 try {
 metadata.inject(bean, beanName, pvs);
 }
 catch (BeanCreationException ex) {
 throw ex;
 }
 catch (Throwable ex) {
 throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
 }
 return pvs;
 }

3). InstantiationAwareBeanPostProcessor :实例化bean后置处理器

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
 /**
 * Apply this BeanPostProcessor <i>before the target bean gets instantiated</i>.
 * The returned bean object may be a proxy to use instead of the target bean,
 * effectively suppressing default instantiation of the target bean.
 * <p>If a non-null object is returned by this method, the bean creation process
 * will be short-circuited. The only further processing applied is the
 ...
 调用机制为bean实例化(Instantiation)之前
 默认null,即什么不做,代表走默认实例化。
 如果返回了bean实例, 则会替代原来正常通过target bean生成的bean的流程. 典型的例如aop返回proxy对象.
 */
 @Nullable
 default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
 return null;
 }
 /**
 * Perform operations after the bean has been instantiated, via a constructor or factory method,
 * but before Spring property population (from explicit properties or autowiring) occurs.
 ...
 //调用时机为bean实例化(Instantiation)之后和任何初始化(Initialization)之前。
 //实例化完了之后,如果这里返回true,代表这个bean的属性会被正常set进去,如果是fa//lse,那么就会跳过,spring给的建议是一般都要返回true。
 */
 default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
 return true;
 }
 /**
 * Post-process the given property values before the factory applies them
 * to the given bean, without any need for property descriptors.
 * <p>Implementations should return {@code null} (the default) if they provide a custom
 * {@link #postProcessPropertyValues} implementation, and {@code pvs} otherwise.
 * In a future version of this interface (with {@link #postProcessPropertyValues} removed),
 * the default implementation will return the given {@code pvs} as-is directly.
 ...
 //调用时机为postProcessAfterInstantiation执行之后并返回true, //返回的PropertyValues将作用于给定bean属性赋值. 
 //spring 5.1之后出现以替换@Deprecated标注的postProcessPropertyValues
 */
 @Nullable
 default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
 throws BeansException {
 return null;
 }
 /**
 * Post-process the given property values before the factory applies them
 * to the given bean. Allows for checking whether all dependencies have been
 * satisfied, for example based on a "Required" annotation on bean property setters.
 * <p>Also allows for replacing the property values to apply, typically through
 * creating a new MutablePropertyValues instance based on the original PropertyValues,
 * adding or removing specific values.
 * <p>The default implementation returns the given {@code pvs} as-is.
 ...
 */
 @Deprecated
 @Nullable
 default PropertyValues postProcessPropertyValues(
 PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
 return pvs;
 }

4). SmartInstantiationAwareBeanPostProcessor :智能实例化bean后置处理器(InstantiationAwareBeanPostProcessor的子类)

public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {
 /**
 * Predict the type of the bean to be eventually returned from this
 * processor's {@link #postProcessBeforeInstantiation} callback.
 * <p>The default implementation returns {@code null}.
 ...
 //预测Bean的类型,返回第一个预测成功的Class类型,如果不能预测返回null
 */
 @Nullable
 default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
 return null;
 }
 /**
 * Determine the candidate constructors to use for the given bean.
 * <p>The default implementation returns {@code null}.
 ...
 // 选择合适的构造器,比如目标对象有多个构造器,在这里可以进行一些定制化,选择合适的构造器
 // beanClass参数表示目标实例的类型,beanName是目标实例在Spring容器中的name
 // 返回值是个构造器数组,如果返回null,会执行下一个PostProcessor的determineCandidateConstructors方法;否则选取该PostProcessor选择的构造器
 */
 @Nullable
 default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
 throws BeansException {
 return null;
 }
 /**
 * Obtain a reference for early access to the specified bean,
 * typically for the purpose of resolving a circular reference.
 * <p>This callback gives post-processors a chance to expose a wrapper
 * early - that is, before the target bean instance is fully initialized.
 * The exposed object should be equivalent to the what
 * {@link #postProcessBeforeInitialization} / {@link #postProcessAfterInitialization}
 * would expose otherwise. Note that the object returned by this method will
 * be used as bean reference unless the post-processor returns a different
 * wrapper from said post-process callbacks. In other words: Those post-process
 * callbacks may either eventually expose the same reference or alternatively
 * return the raw bean instance from those subsequent callbacks (if the wrapper
 * for the affected bean has been built for a call to this method already,
 * it will be exposes as final bean reference by default).
 * <p>The default implementation returns the given {@code bean} as-is.
 ...
 //获得提前暴露的bean引用。主要用于解决循环引用的问题
 //只有单例对象才会调用此方法
 */
 default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
 return bean;
 }
}

可以看出继承InstantiationAwareBeanPostProcessor接口,多了三个方法。这个接口,有一个比较厉害的实现类AbstractAutoProxyCreator,它是AOP实现的核心。在下一个系列中,我们再细说这个类。

3. AbstractAutowireCapableBeanFactory :BeanPostProcessor的入口,spring世界中的生产者

类中方法调用顺序

/**
 * Abstract bean factory superclass that implements default bean creation,
 * with the full capabilities specified by the {@link RootBeanDefinition} class.
 * Implements the {@link org.springframework.beans.factory.config.AutowireCapableBeanFactory}
 * interface in addition to AbstractBeanFactory's {@link #createBean} method.
 *
 * <p>Provides bean creation (with constructor resolution), property population,
 * wiring (including autowiring), and initialization. Handles runtime bean
 * references, resolves managed collections, calls initialization methods, etc.
 * Supports autowiring constructors, properties by name, and properties by type.
 *
 * <p>The main template method to be implemented by subclasses is
 * {@link #resolveDependency(DependencyDescriptor, String, Set, TypeConverter)},
 * used for autowiring by type. In case of a factory which is capable of searching
 * its bean definitions, matching beans will typically be implemented through such
 * a search. For other factory styles, simplified matching algorithms can be implemented.
 *
 * <p>Note that this class does <i>not</i> assume or implement bean definition
 * registry capabilities. See {@link DefaultListableBeanFactory} for an implementation
 * of the {@link org.springframework.beans.factory.ListableBeanFactory} and
 * {@link BeanDefinitionRegistry} interfaces, which represent the API and SPI
 * view of such a factory, respectively.
 ...
 */
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
 implements AutowireCapableBeanFactory {
 /**
 * Central method of this class: creates a bean instance,
 * populates the bean instance, applies post-processors, etc.
 * @see #doCreateBean
 */
 @Override
 protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
 throws BeanCreationException {
 if (logger.isTraceEnabled()) {
 logger.trace("Creating instance of bean '" + beanName + "'");
 }
 RootBeanDefinition mbdToUse = mbd;
 // Make sure bean class is actually resolved at this point, and
 // clone the bean definition in case of a dynamically resolved Class
 // which cannot be stored in the shared merged bean definition.
 Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
 if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
 mbdToUse = new RootBeanDefinition(mbd);
 mbdToUse.setBeanClass(resolvedClass);
 }
 // Prepare method overrides.
 try {
 mbdToUse.prepareMethodOverrides();
 }
 catch (BeanDefinitionValidationException ex) {
 throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
 beanName, "Validation of method overrides failed", ex);
 }
 try {
 // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
 //bean的实例化后前置处理器,如果有,这里会返回代理的实例。AOP的实现基础就是基于这里来实现的
 Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
 //如果不为空 直接返回 修饰后的实例,并中断主线
 if (bean != null) {
 return bean;
 }
 }
 catch (Throwable ex) {
 throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
 "BeanPostProcessor before instantiation of bean failed", ex);
 }
 try {
 //正常创建实例
 Object beanInstance = doCreateBean(beanName, mbdToUse, args);
 if (logger.isTraceEnabled()) {
 logger.trace("Finished creating instance of bean '" + beanName + "'");
 }
 return beanInstance;
 }
 catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
 // A previously detected exception with proper bean creation context already,
 // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
 throw ex;
 }
 catch (Throwable ex) {
 throw new BeanCreationException(
 mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
 }
 }
 ...
 /**
 * Populate the bean instance in the given BeanWrapper with the property values
 * from the bean definition.
 * @param beanName the name of the bean
 * @param mbd the bean definition for the bean
 * @param bw the BeanWrapper with bean instance
 */
 @SuppressWarnings("deprecation") // for postProcessPropertyValues
 protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
 if (bw == null) {
 if (mbd.hasPropertyValues()) {
 throw new BeanCreationException(
 mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
 }
 else {
 // Skip property population phase for null instance.
 return;
 }
 }
 // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
 // state of the bean before properties are set. This can be used, for example,
 // to support styles of field injection.
 boolean continueWithPropertyPopulation = true;
 //BeanDefinition为应用程序bean,而非基础框架bean信息
 //注册过InstantiationAwareBeanPostProcessor类型接口
 if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
 for (BeanPostProcessor bp : getBeanPostProcessors()) {
 if (bp instanceof InstantiationAwareBeanPostProcessor) {
 InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
 if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
 continueWithPropertyPopulation = false;
 break;
 }
 }
 }
 }
 if (!continueWithPropertyPopulation) {
 return;
 }
 PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
 //ioc依赖注入
 if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
 MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
 // Add property values based on autowire by name if applicable.
 if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
 autowireByName(beanName, mbd, bw, newPvs);
 }
 // Add property values based on autowire by type if applicable.
 if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
 autowireByType(beanName, mbd, bw, newPvs);
 }
 pvs = newPvs;
 }
 //容器是否注册了InstantiationAwareBeanPostProcessor
 boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
 // 是否进行依赖检查
 boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
 PropertyDescriptor[] filteredPds = null;
 if (hasInstAwareBpps) {
 if (pvs == null) {
 pvs = mbd.getPropertyValues();
 }
 for (BeanPostProcessor bp : getBeanPostProcessors()) {
 if (bp instanceof InstantiationAwareBeanPostProcessor) {
 InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
 PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
 if (pvsToUse == null) {
 if (filteredPds == null) {
 filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
 }
 pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
 if (pvsToUse == null) {
 return;
 }
 }
 pvs = pvsToUse;
 }
 }
 }
 if (needsDepCheck) {
 if (filteredPds == null) {
 filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
 }
 // 检查是否满足相关依赖关系,对应的depends-on属性,需要确保所有依赖的Bean先完成初始化
 checkDependencies(beanName, mbd, filteredPds, pvs);
 }
 if (pvs != null) {
 //将pvs上所有的属性填充到BeanWrapper对应的Bean实例中
 applyPropertyValues(beanName, mbd, bw, pvs);
 }
 }
 }

总结

  1. BPP是Spring container的一个扩展,在容器初始化bean的过程过,对每个bean都会执行一次,是容器本身的回调行为。ApplicationContext和BeanFactory,处理BPP的时候,有些区别。感兴趣的同学可以看下相关文章。
  2. BeanPostProcessor调用机制为 spring容器实例化bean之后,在执行bean的初始化方法前后。
  3. MergedBeanDefinitionPostProcessor、InstantiationAwareBeanPostProcessor都继承自BeanPostProcessor但是,调用机制不太一样。InstantiationAwareBeanPostProcessor为bean实例化前后,MergedBeanDefinitionPostProcessor为bean实例化后,初始化前执行。
  4. BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的。

这篇文章写起来,很枯燥,很吃力,参考了一些大神的博客,spring官网的文档,加上自己对源码的理解,断断续续大概用了一天的时间,如果有问题,欢迎大家在下方指摘。谢谢!

本来打算这篇文章把上一篇文章提到的问题一次性讲了,但是 背后的东西容太多了,下一篇我们实战下,搞点轻松加愉快的!

参考内容:

  • https://blog.csdn.net/caihaijiang/article/details/35552859
  • https://m.jb51.net/article/139531.htm
  • https://spring.io/projects/spring-boot/
最近发表
标签列表