代码编织梦想

Spring的前置与后置处理器

在提及Spring的时候,很多地方总是会提到前置与后置处理器,本文将对这两种处理器做一下简单的介绍。

前提知识

在这里插入图片描述

Java Config的启动而言,Spring整体的流程大概可以分成两个阶段:解析与实例化

  • 解析:加载各类配置资源并解析配置类的各种注解,最终封装成BeanDefinition,并添加到Spring的BeanDefinitionMap中;
  • 实例化:Spring对这个阶段的处理,是将初始化和初始化分开的。根据BeanDefinition先实例化出Bean对象,再填充对象的各个属性以完成对象完整的初始化,期间可能会发生循环依赖,并且还会在实例化这个阶段多次调用后置处理器。也会进行生命周期的回调。

前置与后置处理器定义

  • 前置处理器:BeanFactoryPostProcessor
  • 后置处理器:BeanPostProcessor

开发者通过实现这两个接口,并通过某种方式注入到Spring内,就可以参与Spring的初始化过程,在其中的某些阶段进行一些定制内容的增加。

这里的前置与后置是相对于Bean的实例化而言的。

前置处理器:BeanFactoryPostProcessor

在Bean对象实例化前,Spring会调用BeanFactoryPostProcessor接口的postProcessBeanFactory

在这个阶段,spring刚刚完成了所有配置类的解析,完整的将所有的配置类转换成了对应的BeanDefinition。但是尚且没有完成Bean的实例化。在这个阶段,程序员可以对这些BeanDefiniton进行二次修改。

postProcessBeanFactory调用

public static void invokeBeanFactoryPostProcessors(
	...
	invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
    ...
}
private static void invokeBeanFactoryPostProcessors(
      Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {

   for (BeanFactoryPostProcessor postProcessor : postProcessors) {
      postProcessor.postProcessBeanFactory(beanFactory);
   }
}

refreshinvokeBeanFactoryPostProcessors里面,通过委托给PostProcessorRegistrationDelegate,最终会进入到上面的方法,在这个方法里面会进行前置处理器的调用。

如果需要更早的调用前置处理器,可以通过实现PriorityOrderedOrdered接口并指定优先级,spring在调用前置处理器的时候,是分类按优先级调用的。

  • 先调用实现PriorityOrderedBeanFactoryPostProcessor,其内优先级越高的越早被调用;
  • 在调用实现OrderedBeanFactoryPostProcessor,其内优先级越高的越早被调用;
  • 最后调用没有实现上面两个接口的BeanFactoryPostProcessor

Spring提供了一些可能会被使用的前置处理器

  • CustomScopeConfigurer:可以用来注册自定义Scope(s)
  • PropertyPlaceholderConfigurer:可以用来读取配置文件中的键值对,替换BeanDefinition中属性的占位符,比如xml文件中经常使用${jdbc.url},原理就是通过这个前置处理器实现的;
  • PropertyOverrideConfigurer:可以对BeanDefinition定义的信息进行覆盖;

后置处理器:BeanPostProcessor

Bean的初始化期间调用,会在各个阶段调用很多次。

简单总结一下调用位置。

1、InstantiationAwareBeanPostProcessor

postProcessBeforeInstantiation方法:反射创建Bean前被调用

这个地方的调用很重要,postProcessBeforeInstantiation后面还会被调用一次,但是和此处的作用是不一样的。

此处调用postProcessBeforeInstantiation如果返回的值不为null:

  • 直接使用该对象完成当前Bean的初始化(这种情况下,就会再调用postProcessAfterInitialization)。

也就是说我们就可以在这里地方决定要不要执行之后的Spring初始化流程。

调用栈

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
 ...
   try {
      // 调用后置处理器:初始化Bean之前,InstantiationAwareBeanPostProcessor,
      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);
   }
...
}
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
   Object bean = null;
   if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
      // Make sure bean class is actually resolved at this point.
      if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
         Class<?> targetType = determineTargetType(beanName, mbd);
         if (targetType != null) {
            bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
            if (bean != null) {
               bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
            }
         }
      }
      mbd.beforeInstantiationResolved = (bean != null);
   }
   return bean;
}
@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
            if (result != null) {
                return result;
            }
        }
    }
    return null;
}

2、SmartInstantiationAwareBeanPostProcessor

determineCandidateConstructors方法:推断构造函数

主要是为了完成Bean对象构造方法的推断,用来反射创建对象

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
   BeanWrapper instanceWrapper = null;
   if (mbd.isSingleton()) {
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }
   if (instanceWrapper == null) {
      //实例化对象(仅仅是生成对象,并非添加到spring单例池中,即目前并没有成为Spring Bean),
      //调用 后置处理器 determineConstructorsFromBeanPostProcessors
         instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
   Object bean = instanceWrapper.getWrappedInstance();
   Class<?> beanType = instanceWrapper.getWrappedClass();
   if (beanType != NullBean.class) {
      mbd.resolvedTargetType = beanType;
   }
    ...
}

createBeanInstance里面调用determineConstructorsFromBeanPostProcessors

@Nullable
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
      throws BeansException {

   if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
            SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
            Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
            if (ctors != null) {
               return ctors;
            }
         }
      }
   }
   return null;
}

3、MergedBeanDefinitionPostProcessor

postProcessMergedBeanDefinition方法:合并BeanDefinition后

doCreateBean调用方法:postProcessMergedBeanDefinition

这个阶段处于MergedBeanDefinition刚刚解析完毕的时候,用来可以进行一些后处理。比如可以在对 bean 的实际实例进行后处理之前准备一些缓存的元数据。

Spring是通过BeanDefinition来初始化对象的,但是在使用BeanDefinition前,需要先进行BeanDefinition的合并。

BeanDefinition可指定父BeanDefinition,子BeanDefinition可继承父BeanDefinition的属性。所以需要合并后的BeanDefinition来实例化Bean。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
   ...
   // Allow post-processors to modify the merged bean definition.
   synchronized (mbd.postProcessingLock) {
      if (!mbd.postProcessed) {
         try {
            //调用后置处理器 MergedBeanDefinitionPostProcessors
            applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
         }
         catch (Throwable ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                  "Post-processing of merged bean definition failed", ex);
         }
         mbd.postProcessed = true;
      }
   }
   ...
}
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
   for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof MergedBeanDefinitionPostProcessor) {
         MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
         bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
      }
   }
}

4、SmartInstantiationAwareBeanPostProcessor

getEarlyBeanReference方法:三级缓存来获取早期对象

这个阶段是将当前创建的对象放到三级缓存内,暂时不会被调用。当出现循环依赖的时候,便需要获取三级缓存,此时会调用getEarlyBeanReference来获取早期引用。而在getEarlyBeanReference就调用了后置处理器的getEarlyBeanReference

此时相当于定义了获取代理对象的方法(后置处理器),但暂时不会调用该后置处理器。

只有在出现循环依赖的时候会执行该后置处理器的处理操作。

  • 出现循环依赖时,需要提前获取对象,所以getEarlyBeanReference方法里,通常是来生成代理来支持AOP。

  • 如果当前初始化的Bean没有出现循环依赖,那么这个后置处理器便不会被调用。而AOP的处理会在其他地方进行。

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){
    ...
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                                        isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        if (logger.isTraceEnabled()) {
            logger.trace("Eagerly caching bean '" + beanName +
                         "' to allow for resolving potential circular references");
        }
        //(是在 getEarlyBeanReference 里面调用的后置处理器 此时此时假如到了三级缓存里面,实际上还没有调用)
        //调用后置处理器,SmartInstantiationAwareBeanPostProcessor 判断是否需要AOP,
        //提前暴露出来,用来解析循环引用,做AOP
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }
    ...   
}
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   Object exposedObject = bean;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
            SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
            exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
         }
      }
   }
   return exposedObject;
}

5、InstantiationAwareBeanPostProcessor

postProcessAfterInstantiation方法:实例化Bean后,属性填充前

属性填充:populateBean里面会进行两次后置处理器的调用。

这个方法处于的阶段在Bean刚刚反射创建出来,但是还没有进行属性填充时。

这个方法的返回值可以决定当前类是否可以作为其他类的属性被注入。默认true

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
    ...
      Object exposedObject = bean;
		try {
			//填充属性(即自动注入) 完成第五次和第六次后置处理器的调用
			// InstantiationAwareBeanPostProcessor.after
			// hasInstantiationAwareBeanPostProcessors
 			populateBean(beanName, mbd, instanceWrapper);
			//完成第七次和第八次后置处理器的调用
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}
     ...
}
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   ...
		//在设置属性之前,让任何 InstantiationAwareBeanPostProcessors 有机会修改 bean 的状态。例如,这可用于支持字段注入样式。
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
						return;
					}
				}
			}
		}
  ...
}

6、InstantiationAwareBeanPostProcessor

postProcessProperties方法:完成属性填充

比如用来支持@Resource@Autowired的两个后置处理器都实现了这个方法。两个后置处理器都实现了不同的属性填充逻辑。

对于开发者而言,可以实现该方法,进而在这个阶段拦截和修改属性。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   ...
       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;
           }
       }
  ...
}

7、InstantiationAwareBeanPostProcessor

postProcessBeforeInstantiation方法:完全初始化Bean前

注意区别第一次的后置处理器调用,和第一次调用的是同一个方法。

在这个阶段Spring借由各个后置处理器完成了以下几件事情:

  • InitDestroyAnnotationBeanPostProcessor@PostConstruct的解析
  • ImportAwareBeanPostProcessor:ImportAware的setImportMetadata方法调用
  • ApplicationContextAwareProcessor:各种Aware接口的方法调用
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    ...
    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        // 第七次调用后置处理器
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }
    ...
}
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
      throws BeansException {

   Object result = existingBean;
   for (BeanPostProcessor processor : getBeanPostProcessors()) {
      Object current = processor.postProcessBeforeInitialization(result, beanName);
      if (current == null) {
         return result;
      }
      result = current;
   }
   return result;
}

8、InstantiationAwareBeanPostProcessor

postProcessAfterInitialization方法:初始化Bean阶段的最后时期

正常初始化对象时,会在这里进行AOP的处理,进行代理操作。

可以查看AbstractAutoProxyCreator对该方法的重写

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
   ...	
   if (mbd == null || !mbd.isSynthetic()) {
      //第八次调用后置处理器,处理器AOP,生成代理对象
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }
   ...
}
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
      throws BeansException {

   Object result = existingBean;
   for (BeanPostProcessor processor : getBeanPostProcessors()) {
      Object current = processor.postProcessAfterInitialization(result, beanName);
      if (current == null) {
         return result;
      }
      result = current;
   }
   return result;
}

9、DestructionAwareBeanPostProcessor

requiresDestruction方法:销毁方法

当前初始化类如果实现了DisposableBean,会注册该方法。

在Spring停止的时候,会调用所有的销毁方法。

protected <T> T doGetBean(
      String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
      throws BeansException {
      ...
      try {
     	 registerDisposableBeanIfNecessary(beanName, bean, mbd);
      }
}    
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_38289451/article/details/122226807

spring的启动过程04-bean后置处理器-爱代码爱编程

概述: spring在初始化bean实例的过程中,需要做个性化的处理如解析注解,每个注解的解析逻辑千变万化有spring自带的有用户自定义的。这里spring就想到了采用注册bean后置处理器的方式处理个性化需求,该种方式类似于intercept功能,又类似于AOP横向切面的概念,因为它同样提供前置处理逻辑及后置处理逻辑,下面具体分析下这种方式的实现过程

spring的后置处理器_虎哥和你一起学编程的博客-爱代码爱编程

        先来讲一下junit配置spring进行单元测试,因为我们的demo就是在这种环境下测试的.         首先用maven引入两个依赖          <dependency> <groupId>junit</groupId> <artifactId>junit</ar

(三)spring-初始化bean的三种方式以及bean的后置处理器_wxd_1024的博客-爱代码爱编程

1、通过@PostConstruct 和 @PreDestroy 方法 实现初始化和销毁bean之前进行的操作 //定义相关的实现类: public class PersonService { private String message; public String getMessage() { retur

spring注解之后置处理器_javxuan的博客-爱代码爱编程_后置处理器的作用

1.BeanPostProcessor后置处理器 bean的后置处理器,该接口有两个方法分别在生命周期的初始化方法前后调用 Factory hook that allows for custom modificat

spring bean前置后置处理器的使用_是kerwin啊的博客-爱代码爱编程_bean的前置处理器和后置处理器在项目中的应用

Spirng中BeanPostProcessor和InstantiationAwareBeanPostProcessorAdapter两个接口都可以实现对bean前置后置处理的效果,那这次先讲解一下BeanPostProcessor处理器的使用 先看一下BeanPostProcessor接口的源码,它定义了两个方法,一个在bean初始化之前,一个在bea

spring 后置处理器+自定义注解+配置文件-爱代码爱编程

后置处理器 如果我们想在Spring容器中完成bean实例化、配置以及其他初始化方法前后要添加一些自己逻辑处理。我们需要定义一个或多个BeanPostProcessor接口实现类,然后注册到Spring IoC容器中

jmeter的前置处理器和后置处理器怎么使用_weixin_34221775的博客-爱代码爱编程

2019独角兽企业重金招聘Python工程师标准>>> 配置元件(config elements )   元件会影响其作用范围内的所有元件。 前置处理程序(Per-processors)   元件在其作用范围内的每一个sampler元件之前执行。 定时器(timers )   元件对其作用范围内的每一个samp

spring 的前置处理器介绍_「已注销」的博客-爱代码爱编程_spring 前置处理器

SpringIOC容器它会以某种方式,加载配置文件中的 信息,将其解析为一个个的BeanDefinition.之后将BeanDefinition注册到容器之中。Spring IOC容器在实现的时候经过的过程可以使用如下图片表

《读spring源码》18 Bean的生命周期简单探索(实现BeanPostProcessor接口下面的前置处理器与后置处理器 )-爱代码爱编程

代码结构: 代码如下: 实现BeanPostProcessor下面的前置处理器和后置处理器 package com.enjoy.cap7; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostP

SpringMVC中传递的数据的前置处理和后置处理-爱代码爱编程

SpringMVC中传递的数据的前置处理和后置处理 在数据的传输过程中,基于数据安全性的考虑,我们往往需要对数据进行编码处理,因此,在前端发送数据前需要对数据进行编码,在后端接收数据时需要进行解码,后端返回数据时同样需要编码处理。因此我们需要利用前置处理器和后置处理器对数据进行系列操作。 下面将利用base64编码描述整个过程(2的6次幂==64):

手写Spring高级源码(六): Spring AOP 应⽤-爱代码爱编程

第六部分 Spring AOP 应⽤   AOP 本质:在不改变原有业务逻辑的情况下增强横切逻辑,横切逻辑代码往往是权限校验代码、⽇志代码、事务控制代码、性能监控代码。   第1节 AOP 相关术语 1.1 业务主线   在讲解AOP术语之前,我们先来看⼀下下⾯这两张图,它们就是第三部分案例需求的扩展(针对这些扩展

spring中的前置处理器和后置处理器区别-爱代码爱编程

背景: SpringIOC容器它会以某种方式,加载配置文件中的 信息,将其解析为一个个的BeanDefinition.之后将BeanDefinition注册到容器之中。Spring IOC容器在实现的时候经过的过程可以使用如下图片表示: 分为两个主要部分: 其一 :容器启动阶段 其二:bean实例化阶段。 在容器的启动阶段主要做的是一些信息收集的

spring后置处理器原理解析-爱代码爱编程

类MyBeanPostProcessor实现了BeanPostProcessor接口。实现方法postProcessBeforeInitialization、postProcessAfterInitialization。将类加进容器,再spring容器中bean初始化的时候就会触发这两个方法。 在spring初始化的时候执行refresh方法,在refre

Spring相关-爱代码爱编程

一、Spring IOC的原理与实现 两个概念 1:控制反转,理论思想,原来的对象是由使用者来控制,有了spring之后,可以把整个对象交给spring来帮我们进行管理。DI:依赖注入,把对应的属性的值填充到具体的对象中,@Autowired,populateBean完成属性值的注入 2:容器,存储对象,使用map结构来存储,在spring中存在三级缓存,

手写模拟实现一个简易Mybatis,支持XML和注解方式查询-爱代码爱编程

本文承接上一文章的小节继续展开Mybatis(调用简图和框架设计思路)+手写模拟mybatis源码分享_喜欢火影的木易杨的博客-CSDN博客 我们结合前面对Mybatis设计的分层结构猜想,参考mybatis源码进行手写,支持通过sqlSession查询数据库,也支持模拟Spring整合扫描@Mapper的注解通过mapper接口直接查询数据库。本小节代

Spring Boot电商项目38:商品模块四:【删除商品】接口;-爱代码爱编程

 说明: (1)本篇博客的内容:开发【删除商品】接口; (2)声明:在实际开项目中,我们不太推荐使用【删除商品】;这是因为,为了保留数据库的信息的沉淀,我们尽量不会去删除这些数据;;;;其实,在业务中,对商品进行下架,就是一种变相的软删除,而且其可以保留历史信息; (3)本篇博客需要注意的点:           ● 【删除商品】时的