手撕Spring后置处理器源码,彻底理解Spring核心
上篇回顾
承接上篇《手撕spring核心源码,彻底搞懂spring流程》。由于上下文之间的逻辑关系,没看过上篇的朋友强烈建议先看上篇。
简单对上篇做个总结:
首先咱们一起写了一个HelloWorld版本的Spring。因为Spring核心是控制反转,就是Bean对象都交给Spring来管理。开发者使用时只需要获取即可。在使用时分为两步:第一步,通过注解配置创建Spring上下文容器;第二步,从中获取需要的Bean来使用。
那讲道理就先把这两步需要的框架构造出来,于是先有了下面的架子:
然后咱们要把这个架子填充血肉,达到真的可以通过注解来使用Spring,进行依赖注入的目标。那首先要把使用到的注解定义出来:
根据这些注解和定义好的框架来实现功能,这是一个有工作经验的开发人员都可以做到的事情。最终的代码为了让大家便于和Spring源码结合,我把名称稍微调整了一下,名称和Spring源码中一致,作用也一致:
spring创建Bean的重点步骤这里面体现了:
1、根据class生成Bean定义
2、根据Bean进行实例化
3、将实例的Bean属性进行填充(autowired的属性实例化)
4、完成Bean对象的创建
实际上spring在将Bean进行实例化到生成Bean对象之前还进行了很多的处理,比如说Bean初始化和Bean增强。AOP和Bean后置处理器有着密切的关系。今天就来重点说一下这部分。
本文的所有代码文字在 https://github.com/xiexiaojing/yuna 里可以找到。
Bean初始化
Spring初始化Bean有三种方式,原理是一样的,分别是:
1、实现InitializingBean接口
2、使用 @PostConstruct 注解
3、或者指定 init-method
<bean
id="testInitializingBean"
class="com.TestInitializingBean"
init-method="testInit">
</bean>
他们同时存在时是有先后顺序的:
执行顺序:
构造器Constructor >
@PostConstruct >
InitializingBean >
init-method
由于上节大量实现了注解方式,三种初始化方式原理大同小异,本篇就手撕 InitializingBean 方式的代码:
先定义一个 InitializingBean 接口,直接从spring-beans的源码把接口定义复制过来即可:
然后找个使用场景,比如Bean实例化后要从远程获取值:
实现也很简单,创建Bean之后加上一个判断+调用:
来看一下效果:
以上就是Spring初始化过程的实现。
Bean的后置处理器
Spring中有两种后置处理器,分别为BeanFactoryPostProcessor和BeanPostProcessor。前者叫bean工厂后置处理器,后者叫bean后置处理器。现在咱们都在讲 Bean ,还没讲到 BeanFactory ,这里不做过多介绍。
后置处理器的作用好像是做木工。先把大体木雕的轮廓做出来,下一步还要进行微调及上色,就是再加工。Spring-AOP 就是通过后置处理器实现的。
那Bean后置处理器的执行时机是什么呢?看了接口定义就明白了。同样,咱们把Spring后置处理器的接口直接复制过来:
这里面有两个方法,一个方法叫:
初始化前,后置处理
一个方法叫:
初始化后,后置处理
咱们就按照方法定义来实现:
注意这里有个 postProcessorList 是我刚刚新定义的,因为Spring不只有一个后置处理器,来提供足够的扩展性:
那Spring什么时候把后置处理器放到这个list里面的呢?扫描的时候放的,举个具体的后置处理器例子:
因为要被扫描到,那一定要是个Component。打印的那两句歌词,我经常用,所以说明一下出处:在《深入理解MQ生产端的底层通信过程-理解channel》里我有把歌曲原唱放上。大学的时候爱听,现在再听已经不觉得好听了。大概是发现结婚这十几年,老公得到了任性的爱情,自己却是那个万般包容的人心里不爽。哈哈哈,开个玩笑,像咱这种普通人,最终在一起的人都是相互包容,相互成就的。
放松了一下,回归正题,扫描后置处理器:
因为后置处理器有严格定义,内部不能绑定Bean,不需要执行初始化,所以可以直接实例化。
运行结果:
这里后置处理器的两个方法各运行了两次,是因为创建了两个Bean:
当然,我们可以指定后置处理器的生效条件,可以不对所有的Bean生效。
这里简单引入一下 AOP ,我也不卖关子了。AOP是通过一个叫
AnnotationAwareAspectJAutoProxyCreator
的后置处理器实现的。里面的很多实现就来判断自己可以代理哪些Bean的。
总结
再来总结一下spring创建Bean的重点步骤:
1、根据class生成Bean定义
2、根据Bean进行实例化
3、将实例的Bean属性进行填充
4、初始化Bean
5、Bean后置处理
6、完成Bean对象的创建
如果我把代码再规整一下,用Spring代码同样的方法命名,大家会发现与Spring源码很多地方已经很接近的。相信对Spring源码的理解是有帮助的。
好了,大家看完这篇文章建议再看一遍我之前的一篇文章:《把对象交给spring管理的3种方法及经典应用》,看看是否对Spring理解更深了?
文章转载自公众号:编程一生