据说你一读Spring源码就懵?我帮你把架子搭好了,你填就行!

有道无术,术尚可求也!有术无道,止于术!

最近断更了一段时间,由于公司比较忙,周五的时候在公司作了一个关于Netty的分享,后续会总结一下分享出来!java

最近一段时间发现常常看到不少人,对Spring源码比较感兴趣,平常开发中,不管你作什么什么项目,大部分都离不开Spring生态的那一套东西,因此不少人对Spring底层源码实现很感兴趣,可是有些历来没有接触过源码的开发者,在看Spring源码的过程当中确实及其难受的,为何,大部分人看源码基本都是debug一点一点去看的,最后发现,越追越离谱,越追越深,到最后都追到JDK源码了,也没有明白是什么意思!web

对于学习源码,个人见解是,先去彻底的熟悉它的用法,想一下若是让你来实现,你会怎么实现!有了这些想法以后,再去看源码去印证你本身的观点,远比你本身去死扣源码快的多。spring

并且,我问过一些读者还有同事,我发现有不少人,看源码容易陷入一个误区,就是刚开始看源码就死扣着一个细节不放,非得搞懂,我并非说这样看源码有什么不对,可是在没有对整个框架有一个全局了解的状况下,不要这样看,你应该先把它的大致框架给搞清楚,在后再分功能一步一步的了解每个功能项!这样作,首先你对整个框架的架构有了一个模糊的认识,再扣细节的途中有时候即便你不知道这个代码在干什么,你也隐约能猜出来,再经过debug 与本身的猜想相互印证,最终达到事半功倍的效果。固然这个建议只针对刚开始看源码的同窗,若是你看的源码不少了,那么你确定又本身的一套学习方法,能够的话,能够在留言区或者私聊做者一块儿交流一下!编程

为了帮助一些萌新们或者想要了解Spring源码的小伙伴,我会把Spring的一些大致逻辑分析一下,细节方面,后续做者也会分享,可是今天这一篇文章,只是为了让你了解整个Spring的骨架!缓存

2、架构图例

Spring生命周期总结

这张图基本的归纳了Spring初始化bean的整个生命周期,包括你们大概熟悉的一些生命周期的回调,以及AOP或者不少大神都分析过的Spring解决循环依赖的三级缓存,看不懂不要紧,后面做者会带着源码一步一步的分析:微信

3、源码分析

1.前期准备

/**
* spring debug
* @author huangfu
*/

public class SpringDebug {
public static void main(String[] args) {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(SpringDebugConfig.class);
}
}

上面这一行代码我估计使用过Spring的人都特别熟悉,若是不熟悉,那我劝你先学会使用,再去深究一些源码的底层逻辑!架构

下面咱们看一下,他到底是如何一步一步的实例化bean,接管bean,而后执行各类生命周期类的!咱们先不妨猜想一下,spring再读取这些bean的时候,关于bean的信息必定是存放在了某一个实体上,那么这个实体是什么呢?这个类就是BeanDefinition那么他存储了什么东西呢?咱们看一下它的子类AbstractBeanDefinition感兴趣的小伙伴本身点进去看一下,做者这里只是为了让你们了解什么是BeanDefinitionapp

image-20200725135718518

里面定义这相似与这样的属性值,固然做者作截取了少数属性,它里面的属性远远比这多得多,它的目的就是bean实例化的时候,须要的数据不须要再经过本身去反射获取,而是再Spring初始化的时候所有读取,须要的时候从这里面拿就行,了解了bd的概念以后,咱们是否疑惑?他读取以后存放在哪里呢?答案是存放再beanFactory里面,因此Spring初始化的时候确定会先实现一个bean工厂!进入到AnnotationConfigApplicationContext里面,你会发下并无初始化,在那初始化呢?众所周知,一个类再初始化的时候会先加载父类的构造函数,因此咱们须要去看一下它的父类GenericApplicationContext:框架

public GenericApplicationContext() {
//初始化bean的工厂
this.beanFactory = new DefaultListableBeanFactory();
}

果真不出我所料,它再父类里面建立了bean工厂,工厂有了,咱们继续回到AnnotationConfigApplicationContext里面往下看:发现它调用了一个this(),说明它调用了本身的空构造方法,因此,咱们进入看一下:编辑器

public AnnotationConfigApplicationContext() {
//初始化读取器
this.reader = new AnnotatedBeanDefinitionReader(this);
//初始化扫描器
this.scanner = new ClassPathBeanDefinitionScanner(this);
}

「至此咱们就能够看对照上面那幅图:初始化的时候bean工厂有了」

image-20200725140629568

「而后再本身的空构造方法里面有初始化了读取器!」

image-20200725140742200

那咱们继续回到AnnotationConfigApplicationContext构造方法里面:

/**
* 建立一个新的AnnotationConfigApplicationContext,从给定的带注释的类派生bean定义
* 并自动刷新上下文。
* @param annotatedClasses one or more annotated classes,
* e.g. {@link Configuration @Configuration} classes
*/

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
//读取Spring内置的几个的class文件转换为bd 而后初始化bean工厂
this();
//这一步就是将配置类Config进行了注册并解析bd
register(annotatedClasses);
//这一步是核心,Spring的理解全在这一步,这一步理解了也就能够说将Spring理解了70%
//内部作一系列的操做如调用bean工厂的后置处理器 实例化类 调用 后置处理器的前置处理 初始化类 调用后置处理器的后置处理 注册事件监听等操做
//完成一个类从class文件变为bean的生命周期
refresh();
}

下一步是调用register方法,干什么呢?试想一下,有时候咱们的自动扫描配置是经过注解@ComponentScan("com.service")来配置的,这个类通常在哪?对了,通常实在配置类中的!

@Configuration
@ComponentScan("com.service")
public class SpringDebugConfig {}

为了可以知道,咱们要扫描那些包下的类,咱们就必须先去解析配置类的BeanDefinition,这样才能获取后续我们要解析的包,固然这个方法不光解析了扫描的包,还解析了其余东西,本文不作讲解!

2.核心功能

好了,再往下走咱们就知道了咱们即将要扫描那些包下的类,让他变成bean,那么咱们继续向下走,走到refresh();这个方法不得了他是整个Springbean初始化的核心方法,了解了它也就可以了解Spring的实例化,回调等一些列的问题,咱们进去看看:

进来以后,咱们一个方法一个方法的分析作了什么功能,首先是:

1). prepareRefresh();

这里是作刷新bean工厂前的一系列赋值操做,主要是为前面建立的Spring工厂不少的属性都是空的,这个方式是为他作一些列的初始化值的操做!

2). obtainFreshBeanFactory()

告诉子类刷新内部bean工厂  检测bean工厂是否存在 判断当前的bean工厂是否只刷新过一次,屡次报错,返回当前使用的bean工厂,当该步骤为xml时 会新建一个新的工厂并返回

3). prepareBeanFactory(beanFactory);

这里是初始化Spring的bean容器,向beanFactory内部注册一些本身自己内置的Bean后置处理器也就是一般说的BeanPostProcessor,这个方法其实也是再初始化工厂!

4). postProcessBeanFactory(beanFactory);

容许在上下文子类中对bean工厂进行后处理,做用是在BeanFactory准备工做完成后作一些定制化的处理! 可是注意,你点进去是空方法,空方法觉得着什么?意味着Spring的开发者但愿调用者自定义扩展时使用!

5). invokeBeanFactoryPostProcessors(beanFactory);

其实相信看名字,大部分读者都可以猜出,他的目的是扫描非配置类的bd注册到工厂里面,扫描完成以后,开始执行全部的BeanFactoryPostProcessors,这里出现了第一个扩展点,自定义实现BeanFactoryPostProcessors的时候,他的回调时机是在Spring读取了所有的BeanDefinition以后调用的,具体的使用方法读者自行百度!

6). registerBeanPostProcessors(beanFactory);

这里是注册bean的后置处理器 也就是  beanPostProcessor 的实现 还有本身内置的处理器  注意这里并无调用该处理器,只是将胡处理器注册进来bean工厂! 不知道你们使用过beanPostProcessor接口这个扩展点吗?他就是再这个方法里面被注册到Spring工厂里面的,固然注意一下,他只是注册进去了,并无执行!记住并无执行!

7). initMessageSource();

怎么说呢,这个方法做者并不许备深究,由于他和本篇文章的意图相违背,他的目的是作一个国际化操做也就是 i18n的资源初始化

8).initApplicationEventMulticaster();

Spring为咱们提供了对于事件编程的封装,通常来讲事件分为三个角色,事件广播器(发布事件),事件监听器(监听事件),事件源(具体的事件信息)三个角色,这个方法的目的就是初始化事件的广播器!

9). onRefresh();

这里又是一个扩展点,内部的方法为空,Spring并无实现它,供调用者实现!

10). registerListeners();

注册Spring的事件监听器,上面已经说过了,这里是初始化而且注册事件监听器

11). finishBeanFactoryInitialization(beanFactory);

这个方法是一个重点,他是为了实例化全部剩余的(非延迟初始化)单例。咱们所说的bean的实例化,注入,解决循环依赖,回调beanPostProcessor等操做都是再这里实现的!

12). finishRefresh();

最后一步:发布相应的事件。Spring内置的事件

至此咱们完成了整个Spring初始化的生命周期骨架,这里做者并无深究里面的实现,只是给读者搭建了一个架子,帮助读者理清Spring的脉络,里面的填充须要读者本身填充!如今回过头去看那个图,是否是就清晰多了?这里我再把那个图放出来,省得大家再翻上去!

Spring生命周期总结

好了,今天的文章到这里也就结束了,做者闲暇时间整理了一份资料,你们有兴趣能够领取下!

才疏学浅,若是文章中理解有误,欢迎大佬们私聊指正!欢迎关注做者的公众号,一块儿进步,一块儿学习!



       
❤️「转发」 「在看」 ,是对我最大的支持❤️



本文分享自微信公众号 - JAVA程序狗(javacxg)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索