【README】

1,本文主要分析 BeanPostProcessor 的作用, 开发方式;

2,BeanPostProcessor 是bean后置处理器, 简而言之就是bean被创建好了,之后如果需要对其属性进行修改,则 需要使用  BeanPostProcessor 来起作用;

3,本文还顺带介绍了  InitializingBean 接口;

啥都不说,先上代码;

4, sprinboot的 后置处理器PostProcessor列表小结(这里只讲了4个):

  1. BeanPostProcessor, bean实例化后的 处理器 ;
  2. InstantiationAwareBeanPostProcessor,实例化装配bean后置处理器,在bean实例化前后干点事情的处理器, 显然执行顺序先于  BeanPostProcessor ;
  3. SmartInstantiationAwareBeanPostProcessor, 智能实例化装配bean后置处理器,同 InstantiationAwareBeanPostProcessor,不过方法比 InstantiationAwareBeanPostProcessor 多;
  4. 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,结果解析

很明显, 程序执行顺序为

  1. bean构造器;
  2. BeanPostProcessor-bean后置处理器的 postProcessBeforeInitialization 方法;
  3. InitializingBean的afterPropertiesSet() 方法;
  4. 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的方法调用顺序为:

  1. bean后置处理器的  postProcessBeforeInitialization ;
  2. 初始化bean接口的  afterPropertiesSet ;
  3. 后置处理器的  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示例及分析相关推荐

  1. SpringBoot自动装配原理分析

    在springBoot中,我们不需要做任何的配置,可以直接编写业务层面的代码,原因就是springBoot帮我们配置好了所有的环境. 下面以一个简单的springboot项目进行分析 项目代码 spr ...

  2. SpringBoot自定义异常源码分析

    SpringBoot自定义异常源码分析 在类上加ControllerAdvice注解,在方法上加ExceptionHandler注解,就可以在方法里处理相应的异常. 1.自定义异常处理类Additio ...

  3. SpringBoot源码笔记分析

    SpringBoot源码笔记分析 1.基础 1.配置SpringBoot热部署 1.引入依赖 <dependency><groupId>org.springframework. ...

  4. php table转json,html table表数据转Json格式示例代码分析

    本文为大家介绍下html table表数据转Json格式,下面有个不错的示例,大家可以参考下 代码如下: var keysArr = new Array("key0", " ...

  5. 串口通信协议示例与分析

    串口通信协议示例与分析     作者:佚名    教程来源:不详    点击数:  变频器与个人电脑使用RS-232/RS-485 串行总线连接,如下所示: 在通讯操作中,通过个人电脑以命令方式控制仪 ...

  6. 微信公众平台开发(二) 微信公众平台示例代码分析

    http://www.cnblogs.com/mchina/archive/2013/06/07/3120592.html 微信公众平台开发(二) 微信公众平台示例代码分析 一.摘要 微信公众平台提供 ...

  7. springboot启动源码分析3-环境配置

    applyInitializersSpringBoot启动源码分析3--环境配置 springboot启动源码分析1--初步初始化 springboot启动源码分析2--run方法分析 springb ...

  8. opencv双目相机标定-示例代码分析

      在这里我使用的是Learning OpenCV3的示例,本节使用的项目代码可以在这里下载到. 一.运行示例   在下载完整个工程以后,按照工程使用说明,下载配置Opencv,运行VS2019项目即 ...

  9. SSM SpringBoot vue智能手机参数分析平台

    SSM SpringBoot vue智能手机参数分析平台 首页 图片轮播 新闻资讯 手机信息 手机百科 登录注册 个人中心 后台管理 登录注册 个人中心 手机百科管理 用户管理 手机对比管理 配置管理 ...

最新文章

  1. 神经网络常用激活函数
  2. 一年的收益就是60% 熊市也能做到 股票花荣实战系统
  3. FCN学习:Semantic Segmentation
  4. linux adb工具_这是一个可以显示Linux命令的工具
  5. 图神经网络PGL助力国民级音乐App,创新迭代千亿级推荐系统(人工智能应用案例)
  6. usaco-sprime-superprime-pass
  7. Pytorch1.7.1与SimpleITK2.0.0在centos7上终端运行冲突的情况
  8. 计算机教学软件cai,计算机毕业论文cai教学软件中数据的分割
  9. 页面导航【WP7学习札记之七】
  10. matplotlib 操作子图(subplot,axes)
  11. Cisco Guard BGP流量牵引配置
  12. Android进阶学习视频
  13. easydarwin 安装_使用EasyDarwin搭建流服务器
  14. 大数据新闻推送你怎么看_人工智能选角大数据推送
  15. 试题 算法训练 调和数列问题---蓝桥杯
  16. Docker 基础之Dockerfile命令详解
  17. 第十一章 性能与可伸缩性 Java并发编程实战 阅读总结
  18. 数据结构和算法学习指南
  19. 28、完美的RestApi
  20. php工程师成长资料

热门文章

  1. P3733 [HAOI2017]八纵八横(线性基/线段树分治)
  2. Rinne Loves Edges
  3. [CodeForces gym 101630 J] 过路费(最短路)
  4. CF1444C-Team-Building【可撤销并查集】
  5. ZOJ1041-Transmitters【差积,计算几何】
  6. 【DP】Rotating Substrings(CF1363F)
  7. 1D/1D动态规划的三种优化方法
  8. Codeforces Gym 101173 CERC 16 D BZOJ 4790 Dancing Disks
  9. Hadoop生态hive(三)Hive QL介绍
  10. Java NIO系列教程(十) Java NIO DatagramChannel