10 年阿里开发架构师经验分享,从入门到精通系列 Java 高级工程师路线介绍
二、Spring 生命周期的大胆猜测
这里分享一个阅读源码的小技巧:捉大放小,连蒙带猜!8 字真言,我们在阅读源码过程中,因为你要知道,每一个被开源出来的优秀框架,其源码的体系都是极其庞大复杂的,我们不能面面俱到,所以在看源码过程中一定不能被细枝末节缠住,一定要先理清楚整个框架的一个大致思想和大致的框架体系,再去搞那些细枝末节,其效率会好很多,其次在看源码过程中,我们一定要大胆的去想,去猜测,如果这个功能让你自己去写,你会怎么实现!
我们今天学习 SpringBean 的生命周期也是按照这个 8 字真言去学习,通过我们之前所学,Spring 大致有以下的功能:
他会帮我们自动的创建对象然后保存起来!
他会帮我们完成属性的填充!
如果我们设置了 Aop 的功能,他会帮我们自动的代理,实现切面功能!
我们从平常的使用中,至少可以得知以上的三点,如果让你自己去实现,必会如何实现呢?
首先他既然能够帮我们自己创建对象,那么他肯定是通过反射来创建的,通过反射来创建,就必定绕不过去要使用 Class 对象创建,那么我们如何获取 Class 对象呢? 去扫描项目,将指定的包下的加了注解的类文件切割获取 Class 名称,通过反射加载 Class 名称,反射创建 java 对象!
我们要完成属性的填充,为了方便和性能方面,我肯定会把这些创建好的对象保存起来,无疑
Map容器是最合适的!我们在创建一个对象完成之后,反射拿到里面的属性,如果需要填充,我们先去我们之前保存的容器里面去取,取不出来在反射吧这个依赖的属性创建出来,然后填充进对象再保存在容器里面,从而完成了属性的注入!
填充完成属性之后,我们那当前对象,取与 Aop 逻辑进行对比,判断是否需要代理,不需要则创建完成,保存进 Map 容器,需要代理则对当前这个类进行
jdk或者cglib的代理然后再保存进容器里面!
于是乎,我们自己实现了一个 Spring 管理一个 Bean 的所有过程,画个图,他大概长这样!
自己实现看起来,整个流程就很清晰,扫描、创建、注入、代理、保存一应俱全,但是 Spring 的实现方式远比我们自己实现的要复杂的多得多!
三、Spring 的生命周期流程
Spring 作者希望,Spring 再着手管理一个 Bean 的时候,它希望能够让 Spring 的使用者能够插手,Spring 把一个类对象变成一个 Java Object 的每一步,怎么理解呢?
比如我们买了一栋新房子,这个房子需要取装修,你自己去装修诚然不够专业,不能够面面俱到,所以是我们就找了一个装修公司帮助我们装修新房,于是装修公司就开始预先画好的图纸进行装修,但是在装修的过程中,你为了让自己的新家更加温馨,你想挂一些壁画在墙上,但是图纸上却没有!于是你就找装修公司,要求装修公司在新家的墙上挂上一些壁画!装修公司在接受到你的请求之后,就吩咐装修的工人在图纸之外去给你在墙上挂上壁画之后,然后再接着装修!
上面这个小故事有 这样几个角色,我们把它和 Spring 对照起来!
你:代表框架的使用者!
新房:代表一个 Class 文件,你自己也能够装修,但是不够专业,所以交给装修公司! 那么你自己创建对象可能某些使用用起来很麻烦,所以我们交给了 Spring 容器!
装修公司:代表着 Spring 容器!
图纸:代表预设步骤,Spring 原本就存在的步骤!
工人:Spring 提供的各种接口!我们可以通过 Spring 工厂提供的接口做各种自定义的配置!
上面的小故事,大致可以描述 Spring 生命周期的核心思想!Spring 再对一个 Class 文件实例化成具体的 Spring Bean 的时候,它提供了各种接口,由我们自己实现!然后再实例化过程中,不同的时机,去调用不同的接口!从而完成 Spring 的整个生命周期的创建!
Spring 的生命周期大致分为以下部分!
扫描项目,将项目指定目录下的 Class 文件转换为 Class 对象!
读取 Class 对象属性包装为
BeanDefinition,然后保存再一个 Map 中!(不难理解,他是为了后续创建或者读取这个类的信息更加方便取而创立的)将全部的类转化为
BeanDefinition并保存之后,开始调用第一个回调接口BeanFactoryPostProcessor#postProcessBeanFactory()!它的调用时机是将扫描到的 Class 文件转换为
BeanDefinition之后调用的,我们可以通过回调的方法获取所有的BeanDefinition,而后续的所有对 Class 的操作都是基于BeanDefinition操作的,所以,我们可以通过修改它,来改变后续的流程!先从当前的容器对象取当前要创建的对象,当取出来的对象为 null 时开始着手创建对象!
做一系列的验证,比如验证这个类是否被排除、是否正在创建中、是否有依赖 Bean【@DependsOn】注解、是否时单例等等!
验证通过之后,开始通过反射创建这个对象!
合并
BeanDefinition,这里涉及到 Spring 之前版本使用的父子容器的概念,属于另外一个知识点不做讲解!判断当前对象是不是单例、是不是支持循环引用、是不是正在创建等!
执行第二个接口回调
InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()方法!它的执行时机时实例化完成之后,属性填充之前,它的返回值是一个布尔值,当返回 false 时,不做自动属性填充!
执行第三个接口回调
InstantiationAwareBeanPostProcessor#postProcessProperties()方法!他的执行时机是,实例化之后,属性填充检查之后,属性填充之前!它会返回一个属性,后续的属性填充会使用这个方法返回的值!我们可以在这个方法里面修改对应 Bean 的注入的值!
填充属性到对象!
调用第四个回调接口
BeanNameAware#setBeanName()方法!调用时机:属性填充给完毕后,调用初始化方法之前;它的功能是能获取 bean 的 Name!
调用第五个回调接口
BeanClassLoaderAware#setBeanClassLoader()调用时机:
BeanNameAware之后,他的功能是传入 bean 的类加载器;调用第六个回调接口
BeanFactoryAware#setBeanFactory()!调用时机:
BeanClassLoaderAware之后,用于设置 beanFactory!调用第七个回调接口
BeanPostProcessor#postProcessBeforeInitialization()方法调用时机是部分
Aware之后,初始化方法之前!传入当前实例化好的对象和 beanName,再初始化前做修改!回调第八个比较重要的生命周期的初始化方法,它可以是一个
InitializingBean接口的 bean,也可以是 xml 中配置的类,也可以是被加了@PostConstruct注解的方法!该方法内部逻辑可以用户自己编写,调用时机为:实例化完成之后调用!
回调第九个回调接口
BeanPostProcessor#postProcessAfterInitialization()方法!该方法的调用时机为初始化方法执行之后,这里也是 Bean 实例化后的最后一步,也是 SpringAop 实现的重要的一步!
注册销毁方法,以便 Spring 容器销毁的时候进行方法的销毁!
整体的方法流程示例图如下:
四、对应源码结构图
读者福利
开源分享:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】
更多笔记分享











评论