手撕Spring后置处理器源码,彻底理解Spring核心

ywz888
发布于 2022-10-9 10:37
浏览
0收藏

上篇回顾

 

承接上篇《手撕spring核心源码,彻底搞懂spring流程》。由于上下文之间的逻辑关系,没看过上篇的朋友强烈建议先看上篇。

 

简单对上篇做个总结:

 

 

首先咱们一起写了一个HelloWorld版本的Spring。因为Spring核心是控制反转,就是Bean对象都交给Spring来管理。开发者使用时只需要获取即可。在使用时分为两步:第一步,通过注解配置创建Spring上下文容器;第二步,从中获取需要的Bean来使用。

 

那讲道理就先把这两步需要的框架构造出来,于是先有了下面的架子:

手撕Spring后置处理器源码,彻底理解Spring核心-鸿蒙开发者社区

然后咱们要把这个架子填充血肉,达到真的可以通过注解来使用Spring,进行依赖注入的目标。那首先要把使用到的注解定义出来:

手撕Spring后置处理器源码,彻底理解Spring核心-鸿蒙开发者社区

根据这些注解和定义好的框架来实现功能,这是一个有工作经验的开发人员都可以做到的事情。最终的代码为了让大家便于和Spring源码结合,我把名称稍微调整了一下,名称和Spring源码中一致,作用也一致:

手撕Spring后置处理器源码,彻底理解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的源码把接口定义复制过来即可:

手撕Spring后置处理器源码,彻底理解Spring核心-鸿蒙开发者社区

然后找个使用场景,比如Bean实例化后要从远程获取值:

手撕Spring后置处理器源码,彻底理解Spring核心-鸿蒙开发者社区

实现也很简单,创建Bean之后加上一个判断+调用:

手撕Spring后置处理器源码,彻底理解Spring核心-鸿蒙开发者社区

来看一下效果:

手撕Spring后置处理器源码,彻底理解Spring核心-鸿蒙开发者社区

以上就是Spring初始化过程的实现。

 

Bean的后置处理器

Spring中有两种后置处理器,分别为BeanFactoryPostProcessor和BeanPostProcessor。前者叫bean工厂后置处理器,后者叫bean后置处理器。现在咱们都在讲 Bean ,还没讲到 BeanFactory ,这里不做过多介绍。

后置处理器的作用好像是做木工。先把大体木雕的轮廓做出来,下一步还要进行微调及上色,就是再加工。Spring-AOP 就是通过后置处理器实现的。

 

那Bean后置处理器的执行时机是什么呢?看了接口定义就明白了。同样,咱们把Spring后置处理器的接口直接复制过来:

手撕Spring后置处理器源码,彻底理解Spring核心-鸿蒙开发者社区

这里面有两个方法,一个方法叫:
初始化前,后置处理

一个方法叫:
初始化后,后置处理

 

咱们就按照方法定义来实现:

手撕Spring后置处理器源码,彻底理解Spring核心-鸿蒙开发者社区

注意这里有个 postProcessorList 是我刚刚新定义的,因为Spring不只有一个后置处理器,来提供足够的扩展性:

手撕Spring后置处理器源码,彻底理解Spring核心-鸿蒙开发者社区

那Spring什么时候把后置处理器放到这个list里面的呢?扫描的时候放的,举个具体的后置处理器例子:

手撕Spring后置处理器源码,彻底理解Spring核心-鸿蒙开发者社区

因为要被扫描到,那一定要是个Component。打印的那两句歌词,我经常用,所以说明一下出处:在《深入理解MQ生产端的底层通信过程-理解channel》里我有把歌曲原唱放上。大学的时候爱听,现在再听已经不觉得好听了。大概是发现结婚这十几年,老公得到了任性的爱情,自己却是那个万般包容的人心里不爽。哈哈哈,开个玩笑,像咱这种普通人,最终在一起的人都是相互包容,相互成就的。

 

放松了一下,回归正题,扫描后置处理器:

手撕Spring后置处理器源码,彻底理解Spring核心-鸿蒙开发者社区

因为后置处理器有严格定义,内部不能绑定Bean,不需要执行初始化,所以可以直接实例化。

 

 

运行结果:

手撕Spring后置处理器源码,彻底理解Spring核心-鸿蒙开发者社区

这里后置处理器的两个方法各运行了两次,是因为创建了两个Bean:

手撕Spring后置处理器源码,彻底理解Spring核心-鸿蒙开发者社区

当然,我们可以指定后置处理器的生效条件,可以不对所有的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理解更深了?

 

文章转载自公众号:编程一生

分类
已于2022-10-9 10:37:59修改
收藏
回复
举报
回复
    相关推荐