关于Spring BeanPostProcessor的执行顺序

目录
  • Spring BeanPostProcessor执行顺序
  • Spring-BeanPostProcessor接口总结
    • 定义
    • BeanPostProcessor
    • BeanPostProcessor总结
    • InstantiationAwareBeanPostProcessor
    • InstantiationAwareBeanPostProcessor总结
    • SmartInstantiationAwareBeanPostProcessor
    • SmartInstantiationAwareBeanPostProcessor总结
    • DestructionAwareBeanPostProcessor
    • DestructionAwareBeanPostProcessor总结
    • 总结一下

Spring BeanPostProcessor执行顺序

首先 Spring 通过调用构造方法创建 User 对象;

User 对象创建好之后,先不直接进行初始化操作,通过 BeanPostProcessor 对刚创建好的 User 对象进行加工操作,其中 postProcessBeforeInitialization 方法的第一个参数是 User 对象,第二个参数是在配置文件中指定的 id 值;

加工好之后通过 return 将对象返回给 Spring 容器,然后 Spring 容器继续按照流程执行 初始化操作,先是 InitializingBean 的初始化操作;

再是 init-method 的初始化;

然后 Spring 容器再次将对象交给 BeanPostProcessor ,执行 postProcessAfterInitialization 方法。

实际上在实战中,我们很少处理 Spring 的初始化操作,所以没有必要区分 Before 还是 After。只需要实现其中的一个即可,显然选 After 方法更好。

先定义一个实体类 Category:

public class Category {
  private Integer id;
  private String name;
  public Integer getId() {
      return id;
  }
  public void setId(Integer id) {
      this.id = id;
  }
  public String getName() {
      return name;
  }
  public void setName(String name) {
      this.name = name;
  }
  @Override
  public String toString() {
      return "Category{" +
              "id=" + id +
              ", name='" + name + '\'' +
              '}';
  }
}

然后注入到 Spring 容器中:

<bean class="edu.lsu.pojo.Category" id="category">
  <property name="id" value="1"/>
  <property name="name" value="迪丽热巴"/>
</bean>

注意此时的名字是迪丽热巴。

此时我们定义一个 BeanPostProcessor,实现他的后置处理器方法:

public class MyBeanPostProcessor implements BeanPostProcessor {
  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      return bean;
  }
  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      Category category = (Category) bean;
      category.setName("古力娜扎");
      return category;
  }
}

当我们在此时的时候,输出结果就是古力娜扎;

@Test
public void test7() {
  ApplicationContext ac = new ClassPathXmlApplicationContext("/applicationContext2.xml");
  Category category = ac.getBean("category", Category.class);
  System.out.println("category = " + category);
}

输出:

category = Category{id=1, name='古力娜扎'}

Spring-BeanPostProcessor接口总结

定义

Spring提供了一个BeanPostProcessor接口,这个接口的作用在于对于新构造的实例可以做一些自定义的修改。比如如何构造、属性值的修改、构造器的选择。

如果想改变Spring容器中bean的一些属性或者行为,可以通过自定义类实现BeanPostProcessor接口实现。

以下基本Spring-beans 5.0.6版本说明。

BeanPostProcessor

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

BeanPostProcessor总结

  • postProcessBeforeInitialization方法的作用在于目标对象实例化之后,初始化之前调用,默认返回原始对象,也可以返回一个包装实例;
  • 如果返回null,接下来的BeanPostProcessors都不会执行
  • postProcessAfterInitialization方法的作用在于目标对象实例化之后,初始化之后调用,默认返回原始对象,也可以返回一个包装实例;
  • 如果返回null,接下来的BeanPostProcessors都不会执行
  • 初始化(Initialization):表示生成对象,未设置属性;初始化之前表示bean的初始化回调之前,如InitializingBean接口的afterPropertiesSet方法或者自定义的init-method方法

InstantiationAwareBeanPostProcessor

InstantiationAwareBeanPostProcessor接口继承自BeanPostProcessor接口,定义了3个方法

@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
 return null;
}
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
 return true;
}
@Nullable
default PropertyValues postProcessPropertyValues(
  PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
 return pvs;
}

InstantiationAwareBeanPostProcessor总结

  • postProcessBeforeInstantiation方法在目标对象实例化之前调用,可以返回一个代理对象来代替目标对象本身;如果返回非null对象,则除了调用postProcessAfterInitialization方法外,其他bean的构造过程都不再调用;
  • postProcessAfterInstantiation方法在对象实例化之后,属性设置之前调用;如果返回值是true,目标bean的属性会被populate,返回false则忽略populate过程;
  • postProcessPropertyValues方法在属性被设置到目标实例之前调用,可以修改属性的设置,PropertyValues pvs表示参数值,PropertyDescriptor[] pds表示目标bean 的属性描述信息,返回值PropertyValues,可以用一个全新的PropertyValues来替代原来的pvs,如果返回null,将忽略属性设置过程;

SmartInstantiationAwareBeanPostProcessor

SmartInstantiationAwareBeanPostProcessor接口继承InstantiationAwareBeanPostProcessor接口,定义了3个方法,作用是在于目标对象的实例化过程中需要处理的事情。

@Nullable
default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
 return null;
}
@Nullable
default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
  throws BeansException {
 return null;
}
default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
 return bean;
}

SmartInstantiationAwareBeanPostProcessor总结

  • predictBeanType方法预测Bean的类型,返回预测成功的Class类型,默认或如果不能预测返回null
  • determineCandidateConstructors方法用于选择合适的构造器,如果类有多个构造器,可以实现这个方法选择合适的构造器并用于实例化对象;该方法在postProcessBeforeInstantiation方法和postProcessAfterInstantiation方法之间调用,如果postProcessBeforeInstantiation方法返回了一个新的实例代替了原本该生成的实例,那么该方法会被忽略;
  • getEarlyBeanReference方法用于解决循环引用问题。比如ReferenceA实例内部有ReferenceB的引用,ReferenceB实例内部有ReferenceA的引用。首先先实例化ReferenceA,实例化完成之后提前把这个bean暴露在ObjectFactory中,然后populate属性,这个时候发现需要ReferenceB。然后去实例化ReferenceB,在实例化ReferenceB的时候它需要ReferenceA的实例才能继续,这个时候就会去ObjectFactory中找出了ReferenceA实例,ReferenceB顺利实例化。ReferenceB实例化之后,ReferenceA的populate属性过程也成功完成,注入了ReferenceB实例。提前把这个bean暴露在ObjectFactory中,这个ObjectFactory获取的实例就是通过getEarlyBeanReference方法得到的;

DestructionAwareBeanPostProcessor

void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;
default boolean requiresDestruction(Object bean) {
 return true;
}

DestructionAwareBeanPostProcessor总结

postProcessBeforeDestruction方法在目标bean被销毁之前调用,该回调适用于单例bean的使用;

判断目标bean是否需要回调postProcessBeforeDestruction方法;

总结一下

Spring内部对象bean的生命周期管理有一套完成的体系,并遵循了设计模式中的开闭原则(开放扩展,关闭修改),如果想修改bean的相关信息,可以通过Spring提供的扩展点,如BeanPostProcessor接口去处理,这样做的好处是不需要关心Spring内部处理逻辑,扩展方便。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Spring bean 加载执行顺序实例解析

    本文研究的主要是Spring bean 加载执行顺序的相关内容,具体如下. 问题来源: 有一个bean为A,一个bean为B.想要A在容器实例化的时候的一个属性name赋值为B的一个方法funB的返回值. 如果只是在A里单纯的写着: private B b; private String name = b.funb(); 会报错说nullpointException,因为这个时候b还没被set进来,所以为null. 解决办法为如下代码,同时学习下spring中 InitializingBean

  • Spring中为bean指定InitMethod和DestroyMethod的执行方法

    1.创建一个类 /** * @author: zhaobin * @date: 2021/11/25 10:16 * @description: */ public class Cat { public Cat(){ System.out.println("先初始化构造器"); } public void start(){ System.out.println("start方法"); } public void destroy(){ System.out.print

  • 关于Spring BeanPostProcessor的执行顺序

    目录 Spring BeanPostProcessor执行顺序 Spring-BeanPostProcessor接口总结 定义 BeanPostProcessor BeanPostProcessor总结 InstantiationAwareBeanPostProcessor InstantiationAwareBeanPostProcessor总结 SmartInstantiationAwareBeanPostProcessor SmartInstantiationAwareBeanPostPr

  • 深入理解Spring Aop的执行顺序

    首先回忆一下 AOP 的常用注解 @Before:前置通知:目标方法之前执行 @After:后置通知:目标方法之后执行 @AfterReturning:返回后通知:执行方法结束前执行 @AfterThrowing:异常通知:出现异常时执行 @Around:环绕通知:环绕目标方法执行 Spring4 中aop正常顺序 + 异常顺序 try{ @Before method.invoke(obj, args); @AfterReturning }catch(){ @AfterThrowing }fin

  • spring初始化方法的执行顺序及其原理分析

    目录 Spring中初始化方法的执行顺序 首先通过一个例子来看其顺序 配置 我们进入这个类看 我们看到了annotation-config了 我们重点看下这行代码 我们直接看initializeBean这个方法 spring加载顺序典例 解决方案 Spring中初始化方法的执行顺序 首先通过一个例子来看其顺序 /**  * 调用顺序 init2(PostConstruct注解) --> afterPropertiesSet(InitializingBean接口) --> init3(init-

  • Spring注解配置AOP导致通知执行顺序紊乱解决方案

    今天在测试Spring的AOP时,发现使用注解配置AOP的方式会导致通知的执行顺序紊乱.[最终通知居然在异常通知之前执行了] 测试代码 (1)定义TargetInterface目标接口 public interface TargetInterface { public abstract void targetProxy(); } (2)定义TargetImpl目标类 @Component("target") public class TargetImpl implements Targ

  • 聊聊Spring AOP @Before @Around @After等advice的执行顺序

    用过spring框架进行开发的人,多多少少会使用过它的AOP功能,都知道有@Before.@Around和@After等advice. 最近,为了实现项目中的输出日志和权限控制这两个需求,我也使用到了AOP功能. 我使用到了@Before.@Around这两个advice.但在,使用过程中,却对它们的执行顺序并不清楚. 为了弄清楚在不同情况下,这些advice到底是以怎么样的一个顺序进行执行的,我作了个测试,在此将其记录下来,以供以后查看. 前提 对于AOP相关类(aspect.pointcut

  • 详解Spring 拦截器流程及多个拦截器的执行顺序

    拦截器是 Spring MVC 中的组件,它可以在进入请求方法前做一些操作,也可以在请求方法后和渲染视图后做一些事情. 拦截器的定义 SpringMVC 的拦截器只需要实现 HandlerInterceptor 接口,并进行配置即可.HandlerInterceptor 接口的定义如下: public interface HandlerInterceptor { default boolean preHandle(HttpServletRequest request, HttpServletRe

  • Spring Cloud Gateway 默认的filter功能和执行顺序介绍

    目录 Spring Cloud Gateway 默认的filter功能和执行顺序 有效性 调试方法 filters(按执行顺序) spring cloud gateway之filter实战 1.filter的作用和生命周期 2.AddRequestHeader GatewayFilter Factory Spring Cloud Gateway 默认的filter功能和执行顺序 有效性 Spring Cloud Gateway 2.0.0.RELEASE 调试方法 新建一个GlobalFilte

  • Spring Aop常见注解与执行顺序详解

    目录 Spring Aop 的常用注解 常见问题 示例代码 配置文件 接口类 实现类 aop 拦截器 测试类 执行结论 多切面的情况 代理失效场景 总结 Spring 一开始最强大的就是 IOC / AOP 两大核心功能,我们今天一起来学习一下 Spring AOP 常见注解和执行顺序. Spring Aop 的常用注解 首先我们一起来回顾一下 Spring Aop 中常用的几个注解: @Before 前置通知:目标方法之前执行 @After 后置通知:目标方法之后执行(始终执行) @After

  • 关于@PostConstruct、afterPropertiesSet和init-method的执行顺序

    目录 @PostConstruct.init-method.afterPropertiesSet() 执行顺序 @PostConstruct 标注的方法在何时被谁调用 init-method.afterPropertiesSet() 的调用 顺序的确定 @PostConstruct.init-method.afterPropertiesSet() 执行顺序 想要知道 @PostConstruct.init-method.afterPropertiesSet() 的执行顺序,只要搞明白它们各自在什

随机推荐