关于Spring BeanPostProcessor的执行顺序
作者:硕子鸽 发布时间:2022-03-17 23:53:41
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


猜你喜欢
- 本文实例为大家分享了Unity实现聊天室功能的具体代码,供大家参考,具体内容如下简单聊天室功能,客户端发送消息后,服务器接收到消息后分发到其
- 一、线程的优先级别线程优先级别的使用范例:package cn.galc.test;public class TestThread6 { p
- Spring定时任务无故停止又不报错一开始是使用Spring自带的定时器来配置定时任务的,简单快捷,配置如下:<bean id=&qu
- 前言序列化想必大家都很熟悉了,对象在进行网络传输过程中,需要序列化之后才能传输到客户端,或者客户端的数据序列化之后送达到服务端序列化的标准解
- 下面分几部分介绍C#实现自动售货机接口的方法,代码写的非常详细,不懂的地方有注释可以参考下。MachineJP类:第1部分:串口初始化,串口
- 有时间我们在使用多线程的时候,需要取消线程的执行,可以使用CancellationTokenSource来取消对Task开辟多线程的取消如下
- 目录一.数组的基本概念二.数组的声明三.数组的创建及初始化1.数组的创建2.数组的初始化四.访问数组元素五.for each 循环六.数组的
- 今天给大家带来的是一个 SpringBoot导入导出数据首先我们先创建项目 注意:创建SpringBoot项目时一定要联网不然会报错项目创建
- 架构:MVC架构基于JWT的身份认证Spring Data (JPA)应用用户密码加密数据库密码加密SQL ServerSlf4j基于Swa
- 在winform里拖入一个datagridview控件,跟一个openfiledialog控件using System;using Syst
- 本文为大家分享了Android基础控件RadioGroup的使用,供大家参考,具体内容如下1.简单介绍RadioGroup可以提供几个选项供
- 这里不准备讨论REST的细节内容,但是总体上,REST是让客户端与服务器段的交互通过发送和接收展示资源的方式来进行,在这里有必要说明:Fie
- using System.Collections.Generic;using System.Text;using System;namesp
- 这篇文章主要介绍了基于Jasypt对SpringBoot配置文件加密,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习
- 这篇文章主要介绍了java多线程关键字final和static详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价
- Redis不仅可作为缓存服务器,还可以用作消息队列。它的列表类型天生支持用作消息队列。如下图所示:由于Redis的列表是使用双向链表实现的,
- 什么是ServletContext?根据字面意思即Servlet上下文服务器会为每一个工程创建一个对象,这个对象就是ServletConte
- 本文实例讲述了Java中的 * 、过滤器、 * 用法。分享给大家供大家参考,具体如下:一、 * :是在面向切面编程的就是在你的servic
- springboots使用的版本是2.0.1,注意不同版本可能有差异,并不一定通用添加Mybatis的起步依赖:<!--mybatis
- import java.io.ByteArrayInputStream; import java.io.FileOutputSt