BeanPostProcessor —— 连接Spring IOC和AOP的桥梁
之前都是从大Boss的视角,来介绍Spring,比如IOC、AOP。
今天换个视角,从一个小喽啰出发,来加深对Spring的理解。
这个小喽啰就是, BeanPostProcessor (下面简称 BBP )。
讲解思路:
- BBP怎么用 —— 先学会怎么用,再去看原理
- BBP的触发时机 —— 在整个Spring Bean初始化流程中的位置
- BBP自己又是什么时候被创建的?
- BBP是如何连接IOC和AOP的?
怎么用
BeanPostProcessor,直译过来,就是“对象后处理器”, 那么这个“后”,是指什么之后呢?
试试便知。
我们先写一个对象,Bean4BBP( 本文的所有代码,可到 Github 上下载 ):
@Component
public class Bean4BBP { private static final Logger log = LoggerFactory.getLogger(Bean4BBP.class); public Bean4BBP(){
log.info("construct Bean4BBP");
}
}
然后再写一个BeanPostProcessor,这时发现它是一个接口,没关系,那就写一个类实现它,CustomBeanPostProcessor:
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor { private static final Logger log = LoggerFactory.getLogger(CustomBeanPostProcessor.class); public CustomBeanPostProcessor() {
log.info("construct CustomBeanPostProcessor");
} @Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof Bean4BBP) {
log.info("process bean before initialization");
}
return bean;
} @Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof Bean4BBP) {
log.info("process bean after initialization");
}
return bean;
}
}
然后启动我们的Spring Boot项目(直接运行Application类),看这几条日志打印的顺序:
construct CustomBeanPostProcessor
construct Bean4BBP
process bean before initialization
process bean after initialization
BBP对象首先被创建,然后创建Bean4BBP对象,接着再先后执行BBP对象的postProcessBeforeInitialization和postProcessAfterInitialization方法。
结论:“对象后处理器”,指的是“ 对象创建后处理器 ”。
我们可以利用它,在对象创建之后,对对象进行修改(有什么场合需要用到?思考题,文末回答。)
那么,为什么要分postProcessBeforeInitialization和postProcessAfterInitialization呢?这里的Initialization是什么意思?
触发时机
我们只需要在CustomBeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法里,打上两个断点,一切自然明了。
断点进来,跟着调用栈这点蛛丝马迹往回走,真相大白: 
在initializeBean方法里面,先后调用了applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization方法,这两个方法内部,则分别去遍历系统里所有的BBP,然后逐个执行这些BBP对象的postProcessBeforeInitialization和postProcessAfterInitialization方法,去处理对象,以applyBeanPostProcessorsBeforeInitialization为例:

那么夹在applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization方法中间的invokeInitMethods方法是做什么的呢?
其实这个方法就是Spring提供的,用于对象创建完之后,针对对象的一些初始化操作。这就好比你创建了一个英雄之后,你需要给他进行一些能力属性的初始化、服装初始化一样。
要验证这一点,很简单,只需让Bean4BBP实现InitializingBean接口:
@Component
public class Bean4BBP implements InitializingBean { private static final Logger log = LoggerFactory.getLogger(Bean4BBP.class); public Bean4BBP(){
log.info("construct Bean4BBP");
} @Override
public void afterPropertiesSet() throws Exception {
log.info("init Bean4BBP");
}
}
然后重新启动工程,打印顺序如下:
construct CustomBeanPostProcessor
construct Bean4BBP
process bean before initialization
init Bean4BBP
process bean after initialization
BBP是什么时候被初始化的
从上面的代码片段,我们已经知道,在对象创建之后,需要遍历BBP列表,对对象进行处理。
这也就意味着, BBP对象,必须在普通对象创建之前被创建 。
那么BBP都是在什么时候被创建的呢?
要回答这个问题,非常简单, 我们只需要在CustomBeanPostProcessor的构造函数里打个断点 (这下看到先学会用,再了解原理的好处了吧)
断点进来,继续利用调用栈,我们找寻到了AbstractApplicationContext的refresh()方法,这个方法里面调用了registerBeanPostProcessors方法,里头就已经把BBP列表创建好了,而普通对象的创建,是在之后的finishBeanFactoryInitialization方法里执行的:

网上有个图画的特别好,很好的展示了BBP在Spring对象初始化流程的位置:

(看到BBP在哪了吗?)
BBP的典型使用 - AOP
不知道大家在使用Spring AOP时,有没有发现,带有切面逻辑的对象,注入进来之后,都不是原来的对象了,比如下图:

调试信息显示,aspectService是一个…$$EnhanceBySpringCGlib的对象,这其实和Spring AOP用到的动态代理有关。
关于Spring AOP的原理,可以参考我之前的回答: 什么是面向切面编程AOP? - Javdroider Hong的回答 - 知乎
这也就意味着, 最终放进Spring容器的,必须是代理对象,而不是原先的对象 ,这样别的对象在注入时,才能获得带有切面逻辑的代理对象。
那么Spring是怎么做到这一点的呢?正是利用了这篇文章讲到的BBP。
显然,我只需要写一个BBP,在postProcessBeforeInitialization或者postProcessAfterInitialization方法中,对对象进行判断,看他需不需要织入切面逻辑,如果需要,那我就根据这个对象,生成一个代理对象,然后返回这个代理对象,那么最终注入容器的,自然就是代理对象了。
这个服务于Spring AOP的BBP,叫做 AnnotationAwareAspectJAutoProxyCreator .
利用idea的diagram功能,可以看出它和BBP的关系:

具体的创建代理对象并返回的逻辑,在postProcessAfterInitialization方法中,大家自行欣赏。
可以说,如果没有BBP,那么Spring AOP就只能叫AOP。
BBP是连接IOC和AOP的桥梁。
总结
这篇文章,主要通过对BBP的讲解,串联起之前讲到的关于Spring的知识,希望能够加深大家对Spring的理解。
最后,回到开头提出的四个问题:
- BBP怎么用 —— 先学会怎么用,再去看原理
- BBP的触发时机 —— 在整个Spring Bean初始化流程中的位置
- BBP自己又是什么时候被创建的?
- BBP是如何连接IOC和AOP的?
BeanPostProcessor —— 连接Spring IOC和AOP的桥梁的更多相关文章
- 【转】spring - ioc和aop
[转]spring - ioc和aop 1.程序中为什么会用到spring的ioc和aop 2.什么是IOC,AOP,以及使用它们的好处,即详细回答了第一个问题 3.原理 关于1: a:我们平常使用对 ...
- J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP
J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP 前言 搜狐畅游笔试题中有一道问答题涉及到回答谈谈对Spring IOC与AOP的理解.特将相关内容进行整理. ...
- Spring IOC及AOP学习总结
一.Spring IOC体系学习总结: Spring中有两个容器体系,一类是BeanFactory.还有一类是ApplicationContext.BeanFactory提供了基础的容器功能.Appl ...
- Spring IOC、AOP、Transaction、MVC小结
1.IOC.AOP:把对象交给Spring进行管理,通过面向切面编程来实现一些“模板式”的操作,使得程序员解放出来,可以更多的关注业务实现. - ...
- 170511、Spring IOC和AOP 原理彻底搞懂
Spring提供了很多轻量级应用开发实践的工具集合,这些工具集以接口.抽象类.或工具类的形式存在于Spring中.通过使用这些工具集,可以实现应用程序与各种开源技术及框架间的友好整合.比如有关jdbc ...
- spring IOC DI AOP MVC 事务, mybatis 源码解读
demo https://gitee.com/easybao/aop.git spring DI运行时序 AbstractApplicationContext类的 refresh()方法 1: pre ...
- spring - ioc和aop
1.程序中为什么会用到spring的ioc和aop 2.什么是IOC,AOP,以及使用它们的好处,即详细回答了第一个问题 3.原理 关于1: a:我们平常使用对象的时候,一般都是直接使用关键字类new ...
- Spring ioc与aop的理解
一 spring的特点 1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦 2.可以使用容易提供的众多服务,如事务管理,消息服务等 3.容器提供单例模式支持 4.容器提供了AOP技术,利用它很容易 ...
- spring IOC与AOP
Spring IOC容器 spring IOC 容器有两种,分别是 BeanFactory 容器和 ApplicationContext 容器. BeanFactory如下: /*第一步,利用Clas ...
随机推荐
- route的简单使用
route [add|del] [-net|-host] target [netmask Nm] [gw Gw] [[dev] If] add : 添加一条路由规则del : 删除一条路由规则-net ...
- JavaSE基础知识(6)—异常和异常处理
一.异常的理解及体系结构图 1.理解 异常:程序运行过程中发生的不正常现象.java中的错误: 语法错误 运行异常 逻辑错误 2.体系图 java程序在执行过程中所发生的异常分为两类: Error:J ...
- tiny4412 --Uboot移植(6) SD卡驱动,启动内核
开发环境:win10 64位 + VMware12 + Ubuntu14.04 32位 工具链:linaro提供的gcc-linaro-6.1.1-2016.08-x86_64_arm-linux-g ...
- Tableau可视化绘图教程
https://www.w3cschool.cn/tableau/tableau_environment_setup.html
- 微信小程序云端解决方案探索之路 - GITC 主题演讲
转自:https://github.com/tencentyun/blog/issues/1 在刚结束的全球互联网技术大会(GITC)里面,我在前端专场给大家分享了「微信小程序云端解决方案探索之路」, ...
- 团队Scrum冲刺阶段-Day 6
选择困难症的福音--团队Scrum冲刺阶段-Day 6 今日进展 编写提问部分 游戏分类的界面全部写完了!!!! 临时大家决定没有BGM的app不是一个完整的app,所以在大家共同学习的努力下,听完四 ...
- 201621123002《java程序设计》第十三周学习总结
1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 为你的系统增加网络功能(购物车.图书馆管理.斗地主等)-分组完成 为了让你的系统可以被多个用户通过网 ...
- AX_CreateAndPostInventJournal
static void CreateAndPostInventJournal(Args _args) { InventJournalTable inventJournalTableLocal; Inv ...
- ajax 与jsp servlet
jQuery的Ajax实现异步传输List.Map_GOOD 分类: JAVA WEB前端2013-08-29 18:35 6296人阅读 评论(0) 收藏 举报 javajquerylistjson ...
- 浅谈如何获取机器的memory和CPU信息
最近做了一个项目,需要获取机器的CPU和memory的使用情况.花了一些时间网上搜索了一下,自己也做了些测试.总结下来,基本上2种方式:一种是用WMI(2种),另一种是用Performance cou ...