关于Spring BeanPostProcessor的执行顺序

作者:硕子鸽 时间:2022-03-17 23:53:41 

Spring BeanPostProcessor执行顺序

关于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内部处理逻辑,扩展方便。

来源:https://wangsuo.blog.csdn.net/article/details/108466628

标签:Spring,BeanPostProcessor,顺序
0
投稿

猜你喜欢

  • Java生成压缩文件的实例代码

    2023-02-04 21:11:09
  • Spring整合Quartz实现定时任务调度的方法

    2023-07-07 00:55:55
  • Java算法实战之排一亿个随机数

    2022-11-22 02:47:26
  • Java 8中字符串拼接新姿势StringJoiner详解

    2022-03-09 03:00:28
  • Springboot整合Shiro的代码实例

    2021-09-03 04:16:52
  • 详解SpringBoot中如何使用布隆过滤器

    2023-11-10 17:43:06
  • 深入理解Java虚拟机体系结构

    2021-09-15 19:46:53
  • Java非侵入式API接口文档工具apigcc用法详解

    2023-11-24 10:01:00
  • 深入理解Spring Boot的日志管理

    2021-11-16 09:58:40
  • Java泛型<T> T与T的使用方法详解

    2021-07-12 10:58:42
  • Java安全之Tomcat6 Filter内存马问题

    2022-11-20 07:29:23
  • java实现MD5加密算法的实例代码

    2021-10-01 16:49:14
  • Java深入讲解异常处理try catch的使用

    2023-11-04 13:00:32
  • Android中TextView显示插入的图片实现方法

    2023-08-06 00:27:42
  • SpringBoot过滤器的使用

    2023-08-28 21:28:56
  • springboot如何使用logback-spring配置日志格式,并分环境配置

    2023-11-10 04:37:34
  • 基于springboot的flowable工作流实战流程分析

    2022-11-28 08:27:09
  • 用Java实现简单画板功能

    2023-01-19 08:17:10
  • springmvc 分页查询的简单实现示例代码

    2022-01-09 11:08:22
  • springboot2启动时执行,初始化(或定时任务)servletContext问题

    2022-10-18 13:14:30
  • asp之家 软件编程 m.aspxhome.com