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 构造器");}@Overridepublic String sayHello() {return "你好我是HelloServiceImpl1";}@Overridepublic 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 {@Overridepublic 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;}@Overridepublic 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 {@AutowiredApplicationContext applicationContext;@Testvoid 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 {@Nullabledefault Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Nullabledefault 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项目进行分析 项目代码 spr ...
- SpringBoot自定义异常源码分析
SpringBoot自定义异常源码分析 在类上加ControllerAdvice注解,在方法上加ExceptionHandler注解,就可以在方法里处理相应的异常. 1.自定义异常处理类Additio ...
- SpringBoot源码笔记分析
SpringBoot源码笔记分析 1.基础 1.配置SpringBoot热部署 1.引入依赖 <dependency><groupId>org.springframework. ...
- php table转json,html table表数据转Json格式示例代码分析
本文为大家介绍下html table表数据转Json格式,下面有个不错的示例,大家可以参考下 代码如下: var keysArr = new Array("key0", " ...
- 串口通信协议示例与分析
串口通信协议示例与分析 作者:佚名 教程来源:不详 点击数: 变频器与个人电脑使用RS-232/RS-485 串行总线连接,如下所示: 在通讯操作中,通过个人电脑以命令方式控制仪 ...
- 微信公众平台开发(二) 微信公众平台示例代码分析
http://www.cnblogs.com/mchina/archive/2013/06/07/3120592.html 微信公众平台开发(二) 微信公众平台示例代码分析 一.摘要 微信公众平台提供 ...
- springboot启动源码分析3-环境配置
applyInitializersSpringBoot启动源码分析3--环境配置 springboot启动源码分析1--初步初始化 springboot启动源码分析2--run方法分析 springb ...
- opencv双目相机标定-示例代码分析
在这里我使用的是Learning OpenCV3的示例,本节使用的项目代码可以在这里下载到. 一.运行示例 在下载完整个工程以后,按照工程使用说明,下载配置Opencv,运行VS2019项目即 ...
- SSM SpringBoot vue智能手机参数分析平台
SSM SpringBoot vue智能手机参数分析平台 首页 图片轮播 新闻资讯 手机信息 手机百科 登录注册 个人中心 后台管理 登录注册 个人中心 手机百科管理 用户管理 手机对比管理 配置管理 ...
最新文章
- 神经网络常用激活函数
- 一年的收益就是60% 熊市也能做到 股票花荣实战系统
- FCN学习:Semantic Segmentation
- linux adb工具_这是一个可以显示Linux命令的工具
- 图神经网络PGL助力国民级音乐App,创新迭代千亿级推荐系统(人工智能应用案例)
- usaco-sprime-superprime-pass
- Pytorch1.7.1与SimpleITK2.0.0在centos7上终端运行冲突的情况
- 计算机教学软件cai,计算机毕业论文cai教学软件中数据的分割
- 页面导航【WP7学习札记之七】
- matplotlib 操作子图(subplot,axes)
- Cisco Guard BGP流量牵引配置
- Android进阶学习视频
- easydarwin 安装_使用EasyDarwin搭建流服务器
- 大数据新闻推送你怎么看_人工智能选角大数据推送
- 试题 算法训练 调和数列问题---蓝桥杯
- Docker 基础之Dockerfile命令详解
- 第十一章 性能与可伸缩性 Java并发编程实战 阅读总结
- 数据结构和算法学习指南
- 28、完美的RestApi
- php工程师成长资料
热门文章
- P3733 [HAOI2017]八纵八横(线性基/线段树分治)
- Rinne Loves Edges
- [CodeForces gym 101630 J] 过路费(最短路)
- CF1444C-Team-Building【可撤销并查集】
- ZOJ1041-Transmitters【差积,计算几何】
- 【DP】Rotating Substrings(CF1363F)
- 1D/1D动态规划的三种优化方法
- Codeforces Gym 101173 CERC 16 D BZOJ 4790 Dancing Disks
- Hadoop生态hive(三)Hive QL介绍
- Java NIO系列教程(十) Java NIO DatagramChannel