抽丝剥茧spring源码(一)

当5G来临,当211高校已经开启人工智能课程,当甲骨文大批量裁人,你们的心是否像我同样为之一颤呢?当科技不断发展,技术迅速迭代,程序员愈发年轻化的今天,而做为咱们已经步入中年的程序员来讲路在何方?当咱们逐渐老去,咱们不能期望企业家的怜悯,当大批年轻化的程序员涌入互联网大潮时,他们的思惟,他们的体能,甚至他们的能力都远超于咱们,咱们又该何去何从?职场不相信眼泪,更不会同情,惟有修炼内功,修炼职场硬实力,固然若是硬实力不行,也只能来点软的了......程序员

做为程序员不懂高并发、JVM优化、系统内核、大数据、框架源码... ...,成天写CRUD,也许很快就会被时代所淘汰。spring

下面让我带你抽丝剥茧spring源码。会从spring ioc容器核心结构、spring ioc注入执行流程的脉络讲起,包括什么是BeanFactory和FactoryBean;什么是BeanDefinition及其有哪些重要的实现类;什么是BeanPostProcessor、BeanFactoryPostProcessor、ImportSelector、ImportBeanDefinitionRegistrar,以及如何应用他们来实现对spring的扩展等等,逐步深刻细节,固然spring源码很是庞大难懂,本文是从spring ioc讲起,重点是梳理spring ioc注入的脉络,以后的博文会一点点抽丝剥茧的对spring内部处理细节作逐步分析讲解,包括Spring aop、spring Tx等等,来逐步解密spring。mybatis

1、带您初识spring容器模型并发

在学习spring ioc源码以前,有必要先了解下其核心类的含义及做用。上面是一个粗略的spring bean工厂内部存储,鉴于spring工厂比较庞大,上图也只画出了一部分比较重要的核心类,可是即使这样这个图片也已经看不清了,可是我会带您一个个讲解说明。框架

初始化spring容器测试代码:函数

    一、首先既然是spring ioc,它的最重要的做用就是管理bean,因此咱们猜想确定是会有一个bean工厂的,这个是不少框架都有的(如mybatis),上来就会来个工厂。这就是                     BeanFactory,在spring中默认的实现类为DefaultBeanFactory,DefaultBeanFactory做为bean工厂的默认实现,主要提供了bean的注册,bean的获取取。固然bean的注册和            获取的具体实现是由其子类AbstractBeanFactory和DefaultSingletonBeanRegistry类完成。高并发

       其实在本文开始的时候我也提到了FactoryBean,那么FactoryBean又是什么的?它是一个spring提供的一个接口,其实你们目前能够简单粗暴的理解为是一个特殊的bean,在某些         状况下bean的实例化过程比较复杂,能够实现FactoryBean接口重写getObject()方法来实现一个复杂bean的实例化,实现FactoryBean接口会在spring工厂中注入2个bean,实现         类自己会对应一个bean,beanName为&+类名(首字母小写),还有一个就是getObject()返回的bean,也就是咱们本身自定义的bean,beanName为返回的Object类的类名            (首字母小写)。如咱们比较熟悉的mybatis就是应用了spring的这个FactoryBean这个扩展类,具体mybatis中的哪一个类应用了,你们本身想吧。post

     二、BeanDefinition:顾名思义,这个类是描述bean的接口。有两个重要的实现类分别是RootBeanDefinition和AnnotatedGenericBeanDefinition。RootBeanDefinition是用来定            义Spring内部的bean,如ConfigurationClassPostProcessor;AnnotatedGenericBeanDefinition是用来定义咱们自定义的bean,也就是咱们注入spring容器,须要spring管理            的bean。学习

     三、说完BeanDefinition,咱们来认识下bean的元数据定义类。ClassMetadata:定义类的元数据,其中包括getClassName、isInterface、isAnnotation方法;                                          MethodMetadata:定义方法的元数据;AnnotationMetadata:定义注解类元数据信息;测试

     四、Spring初始化时bean是怎么存储的?答案是存储在DefaultListableBeanFactory类的集合中,其中BeanDefinitionMap是存储了beanName和BeanDefinition的映射,                          beanDefinitionNames存储了beanName,见下图:

        

        

       

        但请注意此时bean尚未实例化,实例化后,bean是存储在DefaultSingletonBeanRegistry类中的singletonObjects中,这个咱们在以后分析源码的时候会详细说。

        五、AnnotatedBeanDefinitionReader:这个类是spring容器初始化的时候,在DefaultListableBeanFactory初始化以后就会实例化的一个类。它主要的做用是向spring bean工厂中注册咱们自定义的bean,可是这个类实际上是委托了BeanDefinitionReaderUtils类去调用DefaultListableBeanFactory类去完成bean的注册的,可见DefaultListableBeanFactory的重要性。

        六、BeanDefinitionHolder:封装了beanName和BeanDefinition,不用关注。

        七、BeanFactoryPostProcessor:bean工厂的后置处理器,能够插手bean工厂初始化过程,实现这个接口会获得beanFactory实例,也就是能够操做bean工厂了。至于何时会执行其实现类,那是后面博文会讲解的内容。

        八、BeanPostProcessor:bean的后置处理器。会插手bean实例化的过程,实现此接口能够操纵容器中正在初始化的bean,也就是说能够对bean属性作修改。

       九、BeanDefinitionRegistryPostProcessor:是个接口,实现了BeanFactoryPostProcessor接口,定义了postProcessorBeanDefinitionRegistry(registry)方法,也就是扩展了BeanFactoryPostProcessor接口,spring内部ConfigurationClassPostProcessor类实现了这个接口,去完成bean的解析。

        十、实例化AnnotatedBeanDefinitionReader时,同时spring会向容器中注入7个spring自带的bean处理器。这些处理器在spring容器中都起着重要做用。这个也留待咱们以后的博文中进行深刻讲解。

        十一、ClassPathBeanDefinitionScanner:主要用于包的扫描工做。后续博文中会详细说。

        以上简要带你们认识了spring ioc注入过程当中涉及到的一些比较重要的spring核心类。

    

2、Spring ioc初始化流程

下面咱们就以注解方式初始化spring为例讲解下spring容器初始化过程。

 

Spring注解方式启动:实例化AnnotationConfigApplicationContext,传入须要扫描的配置类或须要注入的beanclass。接着咱们就来进入主题,看下源码入口:

2.1实例化父类构造方法

如上图,首先会执行其父类的构造方法,正如我这个方法上注释的说明,主要实例化三个类,咱们分别看下:

GenericApplicationContext:主要实例化了beanFactory,默认为DefaultListableBeanFactory。

AbstractApplicationContext:主要实例化PathMatchingResourcePatternResolver。这个类我在第一部分没有拿出来讲明,其实能够理解它是资源文件解析器,提供了解析资源文件的功能。

 DefaultResourceLoader:实例化类加载器,其实就是APPClassLoader的实例。

执行完父类构造方法后,咱们看下spring容器中的变化,即向spring容器中实例化了:

2.2无参构造方法

父类构造方法执行结束,咱们就来看下主体方法中的第一个方法this()。它会调用无参的构造方法:

经过上面对代码的注解,你应该大体了解了这个构造方法作了什么。下面就在来看下里面的实现。

这个类最终主要会调用AnnotationConfigUtils.registerAnnotationConfigProcessors()方法,也就是AnnotatedBeanDefinitionReader会委托AnnotationConfigUtils类作一些事情,那么咱们就看下registerAnnotationConfigProcessors()方法作了哪些事情。

正如这段代码中我注释所写的那样,主要是向bean工厂中注册spring内部自定义的bean。其中这些bean有的是实现了BeanPostProcessor、BeanFactoryPostProcessor接口的,这两个接口咱们在第一部分中作过说明。被注册的6个bean在后续的操做中都有着各自的做用,这些类会在后续的博文中作详细的介绍。

这里每一个bean都会封装成RootBeanDefinition(这个咱们在第一部分也作过说明,RootBeanDefinition是封装spring内部自定义的bean的),最终会调用registry.registerBeanDefinition(beanName, definition)方法向容器中注册bean。Registry其实就是DefaultListableBeanFactory的实例,那么也就是调用DefaultListableBeanFactory类的registerBeanDefinition()方法:

上面是当前会执行的代码部分,也就是会将那6个bean都注册到beanDefinitionMap

中。这也就是实例化AnnotatedBeanDefinitionReader类主要作的事情。

咱们在来看下如今spring容器中的变化,其实就是bean工厂中注册了7个spring自定义的bean:

上面说了构造函数中的this.reader = new AnnotatedBeanDefinitionReader(this)方法,接下来讲下构造函数中ClassPathBeanDefinitionScanner实例化的过程。

其实这个实例化的过程比较简单,除了实例化ClassPathBeanDefinitionScanner类以外,主要就是注册了几个注解:

暂时能够先不用管这部分,不重要。

此时就完成了spring容器初始化的第一步,再让咱们来看下spring容器目前的状况:

2.3 register(annotatedClasses)注册自定义bean

接下来就要处理咱们须要spring容器来管理的beanclass了。其实就是调用AnnotatedBeanDefinitionReader的register方法,其中参数AnnotatedClasses是咱们传入的须要注入的bean,能够是一个带有@ComponentScan注解的配置类,也能够是一个bean集合,也能够是一个单个bean,因此此处作了循环操做处理。

最终会调用doRegisterBean()方法:

这个方法首先会调用shouldSkip()方法对beanclass作校验,具体校验逻辑见我对代码的注解说明:

接着会调用AnnotationConfigUtils.processCommonDefinitionAnnotations()方法,在这个方法中会给这个bean实例赋予属性,主要是经过这个beanclass上的注解来赋值,会看是否的@Lazy的、@Primary的值、@DependsOn的值、@Role的值、@Description的值,beanclass上存在这些注解就会取值并赋给bean实例。具体实现咱们在以后的博文中会详细分析。

下面是这个方法中最重要的部分,也就是最终的注入。这个以下面第二个图所示,它最终也会调用registry.registerBeanDefinition()方法,也就是DefaultListableBeanFactory类的registerBeanDefinition()方法,最终将annotationClass注入到beanDefinitionMap和BeanDefinitionNames中。这个方法上面有说过,这里就不在说明了,这个方法中具体的细节会在以后的博文中详细分析。

至此咱们的register()方法就处理脉络就说完了,咱们在来看下此时的bean工厂的变化:

其实就是如我上面说的那样将annotationClass(App.class)注入到了咱们的bean工厂中。

2.4 refresh()

上面主要说了spring ioc容器启动过程的前两个方法,下面咱们来看下spring ioc容器启动的最核心最重要的方法refresh()。

下面就让咱们看下refresh()方法都作了什么?

上面是refresh()代码的主体部分,spring ioc容器初始化都会在这里完成,其内部代码很是复杂,这里咱们就先了解下其处理脉络,看下每一个方法都作了什么,在以后的博文中会详细讲解其处理细节。

2.4.1 prepareRefresh()

prepareRefresh():这个方法比较简单,主要是设置了启动时间、启动标识等操做,不是重点,先不用关注。

2.4.2 obtainFreshBeanFactory()

这个方法顾名思义,就是从新获取beanFactory实例,这个方法没有什么可说的,就是获取了以前咱们初始化的beanFactory实例DefaultListableBeanFactory。

GenericApplicationContext:

2.4.3 prepareBeanFactory()

准备bean工厂初始化环境。主要是注入spring内部bean、注册Aware相关接口。

2.4.4 postProcessBeanFactory()

空方法。

2.4.5 invokeBeanFactoryPostProcessors()

这是比较重要的方法之一。其内部处理比较复杂,固然其处理方式是很是值得学习的,想要知道这个方法作了什么吗?下节我将带你们一块儿分析本方法和后续的处理方法的脉络部分。时间不早了,先洗洗睡了。

相关文章
相关标签/搜索