springboot:BeanPostProcessor示例及分析
Posted PacosonSWJTU
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot:BeanPostProcessor示例及分析相关的知识,希望对你有一定的参考价值。
【README】
1,本文主要分析 BeanPostProcessor 的作用, 开发方式;
2,BeanPostProcessor 是bean后置处理器, 简而言之就是bean被创建好了,之后如果需要对其属性进行修改,则 需要使用 BeanPostProcessor 来起作用;
3,本文还顺带介绍了 InitializingBean 接口;
啥都不说,先上代码;
4, sprinboot的 后置处理器PostProcessor列表小结(这里只讲了4个):
- BeanPostProcessor, bean实例化后的 处理器 ;
- InstantiationAwareBeanPostProcessor,实例化装配bean后置处理器,在bean实例化前后干点事情的处理器, 显然执行顺序先于 BeanPostProcessor ;
- SmartInstantiationAwareBeanPostProcessor, 智能实例化装配bean后置处理器,同 InstantiationAwareBeanPostProcessor,不过方法比 InstantiationAwareBeanPostProcessor 多;
- DestructionAwareBeanPostProcessor, bean销毁时的处理器;
【1】 BeanPostProcessor 例子
0,借助 BeanPostProcessor ,InitializingBean 在bean创建完成后 进行日志打印;
1,bean接口与类(类实现了 初始化bean接口InitializeingBean )
public interface HelloService {
public String sayHello();
}
@Service("helloServiceImpl1")
public class HelloServiceImpl1 implements HelloService, InitializingBean {
public HelloServiceImpl1(){
System.out.println("HelloServiceImpl1 构造器");
}
@Override
public String sayHello() {
return "你好我是HelloServiceImpl1";
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("HelloServiceImpl1.afterPropertiesSet() 方法");
}
}
2,后置处理器实现类
/**
* @Description bean后置处理器
* @author xiao tang
* @version 1.0.0
* @createTime 2021年11月14日
*/
@Component
public class HelloPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 非自定义bean,直接返回
if (!(bean instanceof HelloService)) {
return bean;
} else {
// 自定义,打印日志
System.out.printf("bean[%s]初始化前\\n", beanName);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 非自定义bean,直接返回
if (!(bean instanceof HelloService)) {
return bean;
} else {
// 自定义,打印日志
System.out.printf("bean[%s]初始化后\\n", beanName);
}
return bean;
}
}
bean后置处理器作用, 在 bean创建完成后,可以通过 postProcessBeforeInitialization 和
postProcessAfterInitialization 修改bean的属性;
3,测试用例
@SpringBootTest
class Springbt02Config02ApplicationTests {
@Autowired
ApplicationContext applicationContext;
@Test
void contextLoads() throws SQLException {
HelloServiceImpl1 impl1 = (HelloServiceImpl1) applicationContext.getBean("helloServiceImpl1");
System.out.println(impl1.sayHello());
}
}
打印结果:
HelloServiceImpl1 构造器
bean[helloServiceImpl1]初始化前
HelloServiceImpl1.afterPropertiesSet() 方法
bean[helloServiceImpl1]初始化后
你好我是HelloServiceImpl1
4,结果解析
很明显, 程序执行顺序为
- bean构造器;
- BeanPostProcessor-bean后置处理器的 postProcessBeforeInitialization 方法;
- InitializingBean的afterPropertiesSet() 方法;
- BeanPostProcessor-bean后置处理器的 postProcessAfterInitialization 方法;
【2】BeanPostProcessor 方法调用顺序
【2.1】如何走到 postProcessBeforeInitialization() 方法?
1, 路径如下:
从 SpringApplication.run() 方法走;
接着调用 springboot 创建 bean的方法,即 DefaultListableBeanFactory.preInstantiateSingletons() 方法;
然后调用 AbstractAutowireCapableBeanFactory.doCreateBean() 方法创建给定bean;方法参数:
实际创建指定的bean。 预创建处理此时已经发生,例如 检查 postProcessBeforeInstantiation 回调。
区分默认 bean 实例化、工厂方法的使用和自动装配构造函数。protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
创建完成后,调用 AbstractAutowireCapableBeanFactory.initializeBean() 方法初始化给定bean(bean的创建与初始化是 两回事), 方法说明如下:
初始化给定的 bean 实例,应用工厂回调以及 init 方法和 bean 后处理器。
从 createBean 调用传统定义的 bean,从 initializeBean 调用现有 bean 实例。protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
AbstractAutowireCapableBeanFactory.initializeBean() 方法源码;
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 调用bean后置处理器的 postProcessBeforeInitialization() 方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 调用 InitializingBean 的 afterPropertiesSet() 方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 调用bean后置处理器的 postProcessAfterInitialization() 方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
这里非常清楚的说明了 bean后置处理器, 初始化bean的方法调用顺序为:
- bean后置处理器的 postProcessBeforeInitialization ;
- 初始化bean接口的 afterPropertiesSet ;
- 后置处理器的 postProcessAfterInitialization ;
【补充】bean后置处理器
【2.2】 BeanPostProcessor 接口 api
【2.2.1】BeanPostProcessor 类说明
1,允许自定义修改新 bean 实例的工厂钩子 - 例如,检查标记接口或使用代理包装 bean。
通常,通过标记接口等填充 bean 的后处理器将实现 postProcessBeforeInitialization,而使用代理包装 bean 的后处理器通常将实现 postProcessAfterInitialization。
2,登记
ApplicationContext 可以在其 bean 定义中自动检测 BeanPostProcessor bean,并将这些后处理器应用于随后创建的任何 bean。普通的 BeanFactory 允许以编程方式注册后处理器,将它们应用于通过 bean 工厂创建的所有 bean。3,排序
在 ApplicationContext 中自动检测的 BeanPostProcessor bean 将根据 org.springframework.core.PriorityOrdered 和 org.springframework.core.Ordered 语义进行排序。相比之下,使用BeanFactory以编程方式注册的 BeanPostProcessor bean 将使用注册顺序;对于以编程方式注册的后处理器(BeanPostProcessor bean ),会忽略掉实现 PriorityOrdered 或 Ordered 接口的排序。此外,@Order 注释不会被 BeanPostProcessor bean 考虑在内。
// bean后置处理器
public interface 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;
}
}
【2.2.2】 postProcessBeforeInitialization 方法说明
在任何 bean 初始化回调(如 InitializingBean 的 afterPropertiesSet 或自定义初始化方法)之前,将此 BeanPostProcessor 应用于给定的新 bean 实例。
bean 已经被填充了属性值。 返回的 bean 实例可能是原始实例的包装器。
默认实现按原样返回给定的 bean。
说白了 ,就是在 InitiaizingBean.afterPropertiesSet() 之前执行;
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
【2.2.3】 postProcessAfterInitialization 方法说明
说白了 ,就是在 InitiaizingBean.afterPropertiesSet() 之后执行;
在任何 bean 初始化回调(如 InitializingBean 的 afterPropertiesSet 或自定义初始化方法)之后,将此 BeanPostProcessor 应用于给定的新 bean 实例。 bean 已经被填充了属性值。 返回的 bean 实例可能是原始实例的包装器。
在 FactoryBean 的情况下,将为 FactoryBean 实例和 FactoryBean 创建的对象调用此回调(从 Spring 2.0 开始)。 后处理器可以通过相应的 bean instanceof FactoryBean 检查来决定是应用于 FactoryBean 或创建的对象还是两者。
与所有其他 BeanPostProcessor 回调相比,此回调也将在由 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation 方法触发的短路后调用。
默认实现按原样返回给定的 bean。
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
【3】InitializingBean
【3.1】InitializingBean 类说明
由 BeanFactory 设置所有属性后需要响应的 bean 实现的接口:例如 执行自定义初始化,或仅检查是否已设置所有必需属性。
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
【3.1.1】 afterPropertiesSet 方法说明
在设置所有 bean 属性并满足 BeanFactoryAware、ApplicationContextAware 等要求后,由 包裹的BeanFactory 调用。
此方法允许 bean 实例在设置所有 bean 属性后执行其整体配置和最终初始化的验证。
以上是关于springboot:BeanPostProcessor示例及分析的主要内容,如果未能解决你的问题,请参考以下文章
SpringBoot入门到精通-SpringBoot启动流程
SpringBoot入门到精通-SpringBoot自定义starter