【Spring注解驱动开发】关于BeanPostProcessor后置处理器,你了解多少?
写在前面
有些小伙伴问我,学习Spring是不是不用学习到这么细节的程度啊?感觉这些细节的部分在实际工作中使用不到啊,我到底需不需要学习到这么细节的程度呢?我的答案是:有必要学习到这么细节的程度,而且是有机会、有条件一定要学!吃透Spring的原理和源码!往往拉开人与人之间差距的就是这些细节的部分,当前只要是使用Java技术栈开发的Web项目,几乎都会使用Spring框架。而且目前各招聘网站上对于Java开发的要求几乎清一色的都是熟悉或者精通Spring。所以,你,很有必要学习Spring的细节知识点。
项目工程源码已经提交到GitHub:https://github.com/sunshinelyz/spring-annotation
BeanPostProcessor后置处理器概述
首先,我们来看下BeanPostProcessor的源码,看下它到底是个什么鬼,如下所示。
package org.springframework.beans.factory.config;
import org.springframework.beans.BeansException;
import org.springframework.lang.Nullable;
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;
}
}
从源码可以看出:BeanPostProcessor是一个接口,其中有两个方法,postProcessBeforeInitialization和postProcessAfterInitialization两个方法,这两个方法分别是在spring容器中的bean初始化前后执行,所以spring容器中的每一个bean对象初始化前后,都会执行BeanPostProcessor接口的实现类的这两个方法。
也就是说,postProcessBeforeInitialization方法会在bean实例化和属性设置之后,自定义初始化方法之前被调用,而postProcessAfterInitialization方法会在自定义初始化方法之后被调用。当容器中存在多个BeanPostProcessor的实现类时,会按照它们在容器中注册的顺序执行。对于自定义BeanPostProcessor实现类,还可以让其实现Ordered接口自定义排序。
因此我们可以在每个bean对象初始化前后,加上自己的逻辑。实现方式:自定义一个BeanPostProcessor接口的实现类MyBeanPostProcessor,然后在类MyBeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法里面写上自己的逻辑。
BeanPostProcessor后置处理器实例
我们创建一个MyBeanPostProcessor类,实现BeanPostProcessor接口,如下所示。
package io.mykit.spring.plugins.register.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
/**
* @author binghe
* @version 1.0.0
* @description 测试BeanPostProcessor
*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("调用了postProcessBeforeInitialization方法,beanName = " + beanName + ", bean = " + bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("调用了postProcessAfterInitialization,beanName = " + beanName + ", bean = " + bean);
return bean;
}
}
接下来,我们运行BeanLifeCircleTest类的testBeanLifeCircle04()方法,输出的结果信息如下所示。
调用了postProcessBeforeInitialization方法,beanName = animalConfig, bean = io.mykit.spring.plugins.register.config.AnimalConfig$$EnhancerBySpringCGLIB$$e8ab4f2e@56528192
调用了postProcessAfterInitialization,beanName = animalConfig, bean = io.mykit.spring.plugins.register.config.AnimalConfig$$EnhancerBySpringCGLIB$$e8ab4f2e@56528192
Cat类的构造方法...
调用了postProcessBeforeInitialization方法,beanName = cat, bean = io.mykit.spring.plugins.register.bean.Cat@1b1473ab
Cat的postConstruct()方法...
Cat的init()方法...
调用了postProcessAfterInitialization,beanName = cat, bean = io.mykit.spring.plugins.register.bean.Cat@1b1473ab
Cat的preDestroy()方法...
Cat的destroy()方法...
可以看到,postProcessBeforeInitialization方法会在bean实例化和属性设置之后,自定义初始化方法之前被调用,而postProcessAfterInitialization方法会在自定义初始化方法之后被调用。
也可以让实现Ordered接口自定义排序,如下所示。
package io.mykit.spring.plugins.register.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
/**
* @author binghe
* @version 1.0.0
* @description 测试BeanPostProcessor
*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor, Ordered {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("调用了postProcessBeforeInitialization方法,beanName = " + beanName + ", bean = " + bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("调用了postProcessAfterInitialization,beanName = " + beanName + ", bean = " + bean);
return bean;
}
@Override
public int getOrder() {
return 3;
}
}
再次运行BeanLifeCircleTest类的testBeanLifeCircle04()方法,输出的结果信息如下所示。
调用了postProcessBeforeInitialization方法,beanName = animalConfig, bean = io.mykit.spring.plugins.register.config.AnimalConfig$$EnhancerBySpringCGLIB$$b045438a@1ed1993a
调用了postProcessAfterInitialization,beanName = animalConfig, bean = io.mykit.spring.plugins.register.config.AnimalConfig$$EnhancerBySpringCGLIB$$b045438a@1ed1993a
Cat类的构造方法...
调用了postProcessBeforeInitialization方法,beanName = cat, bean = io.mykit.spring.plugins.register.bean.Cat@36c88a32
Cat的postConstruct()方法...
Cat的init()方法...
调用了postProcessAfterInitialization,beanName = cat, bean = io.mykit.spring.plugins.register.bean.Cat@36c88a32
Cat的preDestroy()方法...
Cat的destroy()方法...
BeanPostProcessor后置处理器作用
后置处理器用于bean对象初始化前后进行逻辑增强。spring提供了BeanPostProcessor的很多实现类,例如AutowiredAnnotationBeanPostProcessor用于@Autowired注解的实现,AnnotationAwareAspectJAutoProxyCreator用于SpringAOP的动态代理等等。
除此之外,我们还可以自定义BeanPostProcessor的实现类,在其中写入需要的逻辑。下面以AnnotationAwareAspectJAutoProxyCreator为例,说明后置处理器是怎样工作的。我们都知道springAOP的实现原理是动态代理,最终放入容器的是代理类的对象,而不是bean本身的对象,那么spring是什么时候做到这一步的?就是在AnnotationAwareAspectJAutoProxyCreator后置处理器的postProcessAfterInitialization方法,即bean对象初始化完成之后,后置处理器会判断该bean是否注册了切面,如果是,则生成代理对象注入容器。Spring中的关键代码如下所示。
/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
好了,咱们今天就聊到这儿吧!别忘了给个在看和转发,让更多的人看到,一起学习一起进步!!
项目工程源码已经提交到GitHub:https://github.com/sunshinelyz/spring-annotation
写在最后
如果觉得文章对你有点帮助,请微信搜索并关注「 冰河技术 」微信公众号,跟冰河学习Spring注解驱动开发。公众号回复“spring注解”关键字,领取Spring注解驱动开发核心知识图,让Spring注解驱动开发不再迷茫。
部分参考:https://www.cnblogs.com/dubhlinn/p/10668156.html
【Spring注解驱动开发】关于BeanPostProcessor后置处理器,你了解多少?的更多相关文章
- 【Spring注解驱动开发】BeanPostProcessor在Spring底层是如何使用的?看完这篇我懂了!!
写在前面 在<[String注解驱动开发]面试官再问你BeanPostProcessor的执行流程,就把这篇文章甩给他!>一文中,我们详细的介绍了BeanPostProcessor的执行流 ...
- 0、Spring 注解驱动开发
0.Spring注解驱动开发 0.1 简介 <Spring注解驱动开发>是一套帮助我们深入了解Spring原理机制的教程: 现今SpringBoot.SpringCloud技术非常火热,作 ...
- 【spring 注解驱动开发】spring对象的生命周期
尚学堂spring 注解驱动开发学习笔记之 - 生命周期 生命周期 1.生命周期-@Bean指定初始化和销毁方法 2.生命周期-InitializingBean和DisposableBean 3.生命 ...
- 【spring 注解驱动开发】Spring AOP原理
尚学堂spring 注解驱动开发学习笔记之 - AOP原理 AOP原理: 1.AOP原理-AOP功能实现 2.AOP原理-@EnableAspectJAutoProxy 3.AOP原理-Annotat ...
- 【spring 注解驱动开发】扩展原理
尚学堂spring 注解驱动开发学习笔记之 - 扩展原理 扩展原理 1.扩展原理-BeanFactoryPostProcessor BeanFactoryPostProcessor * 扩展原理: * ...
- 【spring 注解驱动开发】spring ioc 原理
尚学堂spring 注解驱动开发学习笔记之 - Spring容器创建 Spring容器创建 1.Spring容器创建-BeanFactory预准备 2.Spring容器创建-执行BeanFactory ...
- spring注解驱动开发
1.全图: 一.IOC容器部分 1.第一个初始化实例: @Configuration @ComponentScans @Bean("person") 注意: @repeatable ...
- 【Spring注解驱动开发】使用@Scope注解设置组件的作用域
写在前面 Spring容器中的组件默认是单例的,在Spring启动时就会实例化并初始化这些对象,将其放到Spring容器中,之后,每次获取对象时,直接从Spring容器中获取,而不再创建对象.如果每次 ...
- 【Spring注解驱动开发】二狗子让我给他讲讲@EnableAspectJAutoProxy注解
写在前面 最近,二狗子入职了新公司,新入职的那几天确实有点飘.不过慢慢的,他发现他身边的人各个身怀绝技啊,有Spring源码的贡献者,有Dubbo源码的贡献者,有MyBatis源码的贡献者,还有研究A ...
随机推荐
- parrot os vm镜像failed to fetch cdrom apt-get update的问题
vi /etc/apt/sources.list 注释掉第一行 cdrom x保存就可以了
- win10下安装scrapy出现错误的处理
一.背景: 在win10的dos窗口下使用命令pip install scrapy安装scrapy时,出现“ error: Microsoft Visual C++ 14.0 is required. ...
- CentOS 虚拟机 下载及 搭建
个人博客网:https://wushaopei.github.io/ (你想要这里多有) CentOS 虚拟机安装包下载 : 链接:https://pan.baidu.com/s/1JDIASm ...
- 【RT-Thread笔记】BH1750软件包的使用
BH1750简介 BH1750是一种用于两线制串行总线接口的16位数字型光强度传感器集成电路.利用它的高分辨率可以探测较大范围的光强度变化.(1lx~65535lx). 创建工程.验证 在RT-Thr ...
- Java实现 洛谷 P1049 装箱问题
题目描述 有一个箱子容量为V(正整数0≤V≤20000),同时有n个物品(0<n≤30,每个物品有一个体积(正整数). 要求nn个物品中,任取若干个装入箱内,使箱子的剩余空间为最小. 输入输出格 ...
- Java实现 LeetCode 655 输出二叉树(DFS+二分)
655. 输出二叉树 在一个 m*n 的二维字符串数组中输出二叉树,并遵守以下规则: 行数 m 应当等于给定二叉树的高度. 列数 n 应当总是奇数. 根节点的值(以字符串格式给出)应当放在可放置的第一 ...
- Java实现寻找最小的k个数
1 问题描述 有n个整数,请找出其中最小的k个数,要求时间复杂度尽可能低. 2 解决方案 2.1 全部排序法 先对这n个整数进行快速排序,在依次输出前k个数. package com.liuzhen. ...
- java实现第39级台阶(三十九级台阶)
标题: 第39级台阶 小明刚刚看完电影<第39级台阶>,离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级! 站在台阶前,他突然又想着一个问题: 如果我每一步只能迈上1个或2个台阶.先 ...
- Java实现第九届蓝桥杯分数
分数 题目描述 1/1 + 1/2 + 1/4 + 1/8 + 1/16 + - 每项是前一项的一半,如果一共有20项, 求这个和是多少,结果用分数表示出来. 类似: 3/2 当然,这只是加了前2项而 ...
- java实现第六届蓝桥杯显示二叉树
显示二叉树 题目描述 排序二叉树的特征是: 某个节点的左子树的所有节点值都不大于本节点值. 某个节点的右子树的所有节点值都不小于本节点值. 为了能形象地观察二叉树的建立过程,小明写了一段程序来显示出二 ...