springboot:BeanPostProcessor示例及分析

【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 属性后执行其整体配置和最终初始化的验证。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/329807.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实现了某一个接口的匿名类的例子_java中的内部类内部接口详解,一文搞定

简介一般来说&#xff0c;我们创建类和接口的时候都是一个类一个文件&#xff0c;一个接口一个文件&#xff0c;但有时候为了方便或者某些特殊的原因&#xff0c;java并不介意在一个文件中写多个类和多个接口&#xff0c;这就有了我们今天要讲的内部类和内部接口。内部类先讲内…

Java 8 日期和时间解读

转载自 Java 8 日期和时间解读现在&#xff0c;一些应用程序仍然在使用java.util.Date和java.util.Calendar API和它们的类库&#xff0c;来使我们在生活中更加轻松的处理日期和时间&#xff0c;比如&#xff1a;JodaTime。然而&#xff0c;Java 8 引进的新的类库来处理日期和时…

云计算产值将超3000亿美元 亚马逊微软谷歌居三甲

腾讯科技讯 3月27日消息&#xff0c;据外电报道&#xff0c;云计算曾经主要是无法承担建造和维护基础设施的初创公司的解决方案&#xff0c;但对于管理数字业务的大型企业而言&#xff0c;云计算正快速成为省钱的管理数字业务的方式。市场调研公司IDC在上月的一份调查数据显示&…

oracle中join另一个表后会查询不出一些数据_面试必备 | 8个Hive数据仓工具面试题锦集!...

是新朋友吗&#xff1f;记得先点蓝字关注我哦&#xff5e;今日课程菜单Java全栈开发 | Web前端H5大数据开发 | 数据分析人工智能Python | 人工智能物联网进入数据时代&#xff0c;大数据技术成为互联网发展的核心要素之一。与此同时大数据开发工程师的薪资也成为行业内高薪的代…

springboot-Initializer例子及分析

【README】 1&#xff0c;本文主要编写了 初始化器例子并分析了其调用路径&#xff1b; 2&#xff0c;初始化器的执行顺序 先于 后置处理器&#xff1b; 后置处理器&#xff0c;refer2 springboot&#xff1a;BeanPostProcessor示例及分析_PacosonSWJTU的博客-CSDN博客【RE…

ASP.NET 开发人员不必担心 Node 的五大理由

哦别误会……我真的很喜欢 Node&#xff0c;而且我觉得它提出的概念和模式将在很长一段时间内&#xff0c;对服务端 Web 编程产生深远的影响。即使随着时间的推移 Node 过气了&#xff0c;我们肯定可以从下一个牛逼玩意身上或多或少的感觉到它的影响(不管好的和/或坏的)。而在这…

Spring Boot面试题

转载自 Spring Boot面试题 Spring Boot 是微服务中最好的 Java 框架. 我们建议你能够成为一名 Spring Boot 的专家。问题一 Spring Boot、Spring MVC 和 Spring 有什么区别&#xff1f; SpringFrameSpringFramework 最重要的特征是依赖注入。所有 SpringModules 不是依赖注入就…

synchronized原理_Java并发编程 -- synchronized保证线程安全的原理

线程安全是并发编程中的重要关注点&#xff0c;应该注意到的是&#xff0c;造成线程安全问题的主要诱因有两点&#xff0c;一是存在共享数据(也称临界资源)&#xff0c;二是存在多条线程共同操作共享数据。因此为了解决这个问题&#xff0c;我们可能需要这样一个方案&#xff0…

转:Java 7 种阻塞队列详解

转自&#xff1a; Java 7 种阻塞队列详解 - 云社区 - 腾讯云队列&#xff08;Queue&#xff09;是一种经常使用的集合。Queue 实际上是实现了一个先进先出&#xff08;FIFO&#xff1a;First In First Out&#xff09;的有序表。和 List、Set ...https://cloud.tencent.com/de…

微软Build 2016前瞻:让开发者编写能畅行所有设备的app

本周三&#xff0c;5000名软件开发者将齐聚旧金山莫斯康展览中心参加微软公司年度开发者大会&#xff08;Build 2016&#xff09;&#xff0c;和往年一样&#xff0c;微软在大会上发布了一系列新的技术支持。 据透露&#xff0c;微软将会让开发人员编写可以在任何Windows设备上…

XSS的那些事儿

转载自 XSS的那些事儿XSS是什么XSS&#xff0c;Cross-site scripting&#xff0c;跨站脚本攻击&#xff0c;为了区分与CSS&#xff0c;起名为XSS。黑客利用网站的漏洞&#xff0c;通过代码注入的方式将一些包含了恶意攻击脚本程序注入到网页中&#xff0c;企图在用户加载网页时…

js 时间戳转换成时间_JavaScript 时间戳转成日期格式

我们在开发中经常需要把时间戳转化成日期格式&#xff0c;但 JavaScript 本身自带的 Date 方法并不像 PHP date 的那么强大。因此&#xff0c;我们就需要自己动手写一个方法。首先我们要先了解下需要用到的 JavaScript 自带的 Date 对象的方法&#xff1a;getDate&#xff1a;获…

java阻塞队列小结

【README】 1&#xff0c;本文介绍了java的7个阻塞队列&#xff1b; 2&#xff0c;阻塞队列的作用 做缓冲作用&#xff0c;如缓冲kafka消息&#xff0c;而不是直接发送给kafka&#xff0c;减少kafka集群的压力&#xff1b;【1】阻塞队列 BlockingQueue 概述 1&#xff0c;队…

来自.NET FM的感谢信

掐指一算&#xff0c;我们的播客 .NET FM 已经上线一周了&#xff01;&#xff01;&#xff01;不过瞅下节节攀升的流量&#xff0c;二位主播一边感叹 .NET 中文社区的热情&#xff0c;一边摸了摸瘪下去的荷包&#xff1a; • 首日访问 > 2000人次 • 五日访问 > 5000人次…

并发场景下MySQL存在的问题及解决思路

转载自 并发场景下MySQL存在的问题及解决思路 目录1、背景2、表锁导致的慢查询的问题3、线上修改表结构有哪些风险&#xff1f;4、一个死锁问题的分析5、锁等待问题的分析6、小结 一、背景对于数据库系统来说在多用户并发条件下提高并发性的同时又要保证数据的一致性一直是数据…

python queue 生产者 消费者_【python】-- 队列(Queue)、生产者消费者模型

队列(Queue)在多个线程之间安全的交换数据信息&#xff0c;队列在多线程编程中特别有用队列的好处&#xff1a;提高双方的效率&#xff0c;你只需要把数据放到队列中&#xff0c;中间去干别的事情。完成了程序的解耦性&#xff0c;两者关系依赖性没有不大。一、队列的类型&…

关于.NET技术前途问题的讨论

我去年曾经在论坛发起过关于.NET技术前途问题这个话题的讨论&#xff0c;也引起了很多同行和朋友的回复&#xff0c;时间过去大半年&#xff0c;自己也有了一些新的理解。本文的目的就是将其中一些精彩的观点整理出来并谈谈自己的观点。 引子 我们都知道微软.NET技术更新速度快…

用枚举enum实现单例

【README】 1&#xff0c;effectivejava 讲到使用 枚举类实现单例的例子&#xff0c;非常好用&#xff1b;2&#xff0c;好处如下&#xff1a; 不用定义私有构造器&#xff1b;不用定义获取单例的方法&#xff0c;如 getInstance() &#xff1b;通过 枚举类.INSTANCE() 就可以…

前端面试常考系列一

转载自 前端面试常考系列一 一、简述HTML5的优点和缺点&#xff1f; 优点&#xff1a; 1、网络标准统一、HTML5是由W3C推出的。 2、多设备、跨平台 &#xff0c;移植性强。 3、自适应网页设计。 4、即时更新。 5、新增了几个标签&#xff0c;有助于开发人员定义重要的内容&…

基于轻量型Web服务器Raspkate的RESTful API的实现

在上一篇文章《Raspkate - 基于.NET的可运行于树莓派的轻量型Web服务器》中&#xff0c;我们已经了解了Raspkate这一轻量型Web服务器&#xff0c;今天&#xff0c;我们再一起了解下如何基于Raspkate实现简单的RESTful API。 模块 首先让我们了解一下“模块”的概念。Raspkate的…