博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring后置处理器BeanPostProcessor的应用
阅读量:4109 次
发布时间:2019-05-25

本文共 5413 字,大约阅读时间需要 18 分钟。

前言

最近在恶啃Spring源码,就读到一个很有意思的东西BeanPostProcessor,正式的名字叫做Spring后置处理器,这个东西非常的强大,强大到可以让我们干预Bean的创建过程,写出来分享给大家。更多Spring内容进入。

BeanPostProcessor

BeanPostProcessor是Spring框架提供的一个扩展类点,叫做bean后置器。通过实现BeanPostProcessor接口,程序员就可以干预bean实例化的过程,从而减轻beanFactory的负担。这个接口可以设置多个,形成一个列表,然后依次执行。注意凡是实现BeanPostProcessor接口的全部都会执行一遍。那么这个东西这么牛逼,它有什么Spring的应用实例嘛?其实我们一直用的AOP就是用这个接口在Bean实例化期间,将切面逻辑植入Bean实例中的。也正是通过BeanPostProcessor,Spring把AOP,动态代理,IOC容器建立起了联系。

操作BeanPostProcessor

上面吹了一堆这个东西这么牛逼,就得实际看看这个东西道理怎么样。于是我们就得

在这里插入图片描述
假如有个配置类AppConfig,再整一个业务类IndexDao,还有一个测试类:

@Configuration@ComponentScan("com.demo")public class AppConfig {
}
@Repositorypublic class IndexDao {
public IndexDao() {
System.out.println("Constructor"); } @PostConstruct public void init(){
System.out.println("init"); } public void query(){
System.out.println("query"); }}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext anno= new AnnotationConfigApplicationContext(AppConfig.class); IndexDao dao=anno.getBean(IndexDao.class); dao.query(); }}

这个例子里面注解@PostConstruct是Spring声明周期回调的初始化方法,笔者在这里有详解,有兴趣的各位可以去看下。下面我们开始正片。

BeanPostProcessor接口

新建一个类继承BeanPostProcessor接口,然后有两个实现方法,我们给实现了。因为Java 8中添加了默认的实现字符default,在最新的Spring版本中把这两个方法都加了default默认符,因此需要用快捷键把他们调出来。先讲解一下参数,第一个参数Object bean这里传入的就是我们要寻找的bean,比如我在Test里调用了IndexDao.class,在Spring容器里就会把IndexDao传到这个方法里做事情,只不过Spring调用对程序员来说是黑盒子不用管而已。第二个参数String beanName,自然就是这个bean的名字,没什么可以解释的。Spring底层存储这些bean是类似一个map存储解构存的,差不多就是map<BeanName,BeanDefinitation>这样的解构,因此这里拿到这些非常方便。我的这个例子就是当发现传入的是indexDao的时候,就执行一些事情,为了避免Spring自己的东西干扰,因此做了一个处理。

public class TestBeanPostProcessor implements BeanPostProcessor{
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("indexDao")){
//特指indexDao时触发 System.out.println("postProcessBeforeInitialization + IndexDao"); } return bean; //返回该bean } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("indexDao")){
System.out.println("postProcessAfterInitialization + IndexDao"); } return bean; }}

上面一共两个方法,看名字一个是before,一个是after。顾名思义一个是初始化之前被调用的,一个就是初始化之后被调用的。那么我们运行一下Test看看效果:

运行结果:ConstructorpostProcessBeforeInitialization + IndexDaoinitpostProcessAfterInitialization + IndexDaoquery

看输出确实是在初始化方法前后执行的,那么到了这里大家是否有一些对于Spring AOP的感悟,Spring AOP是怎么做的,就是创建一个新的代理返回出去对不对。我们也可以做啊,只要在bean初始化之前修改返回就可以干预这个bean的生成,比如下面的修改:

@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("indexDao")){
System.out.println("postProcessBeforeInitialization + IndexDao"); }
<这里是伪码>
//这里可以直接把对象重新复写成代理对象返回去,这样就干预了IndexDao的初始化,变成了IndexDaoProxy。 return Proxy.newIndexDaoProxy();}

AOP不就是这么做的么,我们实例化一个A,但是我们拿到的是一个代理B,代理B执行了代理方法和A里面的业务方法。现在我们在实例化A的时候,对A进行加工做成B,然后把B返回出去,不就做到了Spring AOP的过程。是不是有种刷新了认知的感觉。

PriorityOrdered接口

这是一个小扩展,也是整BeanPostProcessor的时候发现的。这个接口可以改变BeanPostProcessor的顺序。怎么说呢,我们修改一下TestBeanPostProcessor让其实现PriorityOrdered接口,然后实现里面的getOrder()方法。然后再复制一个TestBeanPostProcessor1的类,修改一下输出:

@Componentpublic class TestBeanPostProcessor implements BeanPostProcessor , PriorityOrdered {
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("indexDao")){
System.out.println("postProcessBeforeInitialization + IndexDao"); } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("indexDao")){
System.out.println("postProcessAfterInitialization + IndexDao"); } return bean; } @Override public int getOrder() {
return 15; //这个值随便写的 }}
@Componentpublic class TestBeanPostProcessor1 implements BeanPostProcessor, PriorityOrdered {
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("indexDao")){
System.out.println("postProcessBeforeInitialization1 + IndexDao"); } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("indexDao")){
System.out.println("postProcessAfterInitialization1 + IndexDao"); } return bean; } @Override public int getOrder() {
return 11; }}运行输出:ConstructorpostProcessBeforeInitialization1 + IndexDaopostProcessBeforeInitialization + IndexDaoinitpostProcessAfterInitialization1 + IndexDaopostProcessAfterInitialization + IndexDaoquery

对比输出结果,发现TestBeanPostProcessor1先执行了。我们接着修改TestBeanPostProcessor1.getOrder()方法,再执行:

TestBeanPostProcessor1里面的:@Overridepublic int getOrder() {
return 100;}运行输出:ConstructorpostProcessBeforeInitialization + IndexDaopostProcessBeforeInitialization1 + IndexDaoinitpostProcessAfterInitialization + IndexDaopostProcessAfterInitialization1 + IndexDaoquery

运行输出的结果就把postProcessBeforeInitialization1调到后面去了。其实PriorityOrdered就是调整Bean创建优先顺序的接口,其中getOrder()值越小,优先权越高。

结语

最近开始啃Spring源码,啃的越多也觉得自己的水平和小白越近,马上都快不会写代码了。但是源码干涩,难以下咽,等笔者消化消化有了新的发现再分享出来,有问题的地方欢迎读者老爷们指正,谢谢大家阅读。

转载地址:http://vtmsi.baihongyu.com/

你可能感兴趣的文章
codeforces -420-B. Okabe and Banana Trees
查看>>
codeforces 420-C. Okabe and Boxes
查看>>
数据结构--线性表的顺序表示及操作
查看>>
UVA 658 It's not a Bug, it's a Feature!
查看>>
Educational Codeforces Round 27-C. Two TVs
查看>>
UVA-1658 Admiral
查看>>
二维几何基础--向量的表示及简单运算
查看>>
向量运算-叉积,点积
查看>>
点-线,线-线
查看>>
That Nice Euler Circuit UVALive - 3263
查看>>
7-9 拯救007
查看>>
7-3 古风排版
查看>>
7-14 最小生成树的唯一性
查看>>
7-11 肿瘤诊断
查看>>
7-8 整除光棍
查看>>
7-16 喊山
查看>>
7-13 地下迷宫探索
查看>>
Tree UVA - 548
查看>>
L2-006. 树的遍历
查看>>
L2-011. 玩转二叉树
查看>>