spring源码解析(一)spring容器启动的十六个步骤

前序

spring 是java技术系列公认的最优秀的源码,甚至没有之一 。。。那么我们平时在用到spring框架大部分都是会使用注解或者配置的方式。。但是具体其中的原理也都是似懂非懂,包括本人在内,之前只会使用一些spring的注解或者配置方式,又或者是会使用spring的扩展机制来做一些高级功能,,,学习原理最好的方式还是来读懂并且调试spring源码最直接。。。同时对于我们以后去读其他开源代码也有巨大帮助,,,小编觉得spring源码的思想被很多开源代码所采纳。。故可举一反三。。。本文将简单介绍spring启动的十六个步骤,,后续的文章会介绍每一个模块的作用

 

为什么要学习spring源码:

  • 深入学习过源码后,自己在使用的时候显得更游刃有余。
  • 可以学习到一些优秀的代码,比如设计模式和代码整洁。
  • 许多中间件如dubbo都会基于 Spring 的扩展功能来实现,阅读 Spring 源码,能帮助你更好的阅读中间件源码。
  • 应付面试。

怎么学习spring的源码:

1.要有耐心,,我们可以先弄懂spring大概的生命周期。。然后针对每一个步骤逐个突破,,,

2.有些部分,可能你看到会有疑惑,没有关系,小编觉得要硬着头皮看下去,因为可能你看到后面某个点,对前面的就理解了。

3.我们尽量在学习源码的时候加上我们自己的注释,,,这样有利于我们之后再去理解,复习。。。

4.如果在阅读过程中有不理解的,可以debug 来调试,这样直观且容易记住过程。。。

 

正文

通常我们启动一个spring容器有两种方式,,

第一种是传统的spring启动方式-利用web.xml来启动容器。。

如:

       org.springframework.web.context.ContextLoaderListener

ContextLoaderListener 是实现了 javax.servlet.ServletContextListener 接口的服务器端程序,随 web 应用的启动而启动,只初始化一次,随 web 应用的停止而销毁。在web应用启动的时候会调用 contextInitialized 方法,停止的时候会调用 contextDestroyed 方法。
第二种就是springboot的启动方式如下:

spring源码解析(一)spring容器启动的十六个步骤_第1张图片

 

我们点击new AnnotationConfigApplicationContext源码可以发现这三步:

spring源码解析(一)spring容器启动的十六个步骤_第2张图片

第一步:调用的是无参构造方法AnnotationConfigApplicationContext如下

spring源码解析(一)spring容器启动的十六个步骤_第3张图片

在构造AnnotationConfigApplicationContext时,会先调用父类GenericApplicationContext的构造方法,GenericApplicationContext会初始化一个beanFactory,默认值为DefaultListableBeanFactory,如下:

spring源码解析(一)spring容器启动的十六个步骤_第4张图片

从中我们可以看出,这个方法就是new 一个DefaultListableBeanFactory,然后会在里面存一个beanDefinitionMap,根据名字可以看出,它放置的是一些关于注解的默认的后置处理器的beandefinition...

AnnotationConfigApplicationContext的类结构图

spring源码解析(一)spring容器启动的十六个步骤_第5张图片

  1. new RootBeanDefinition(ConfigurationClassPostProcessor.class);
  2. new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
  3. new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
  4. new RootBeanDefinition(EventListenerMethodProcessor.class);
  5. new RootBeanDefinition(DefaultEventListenerFactory.class);

重点关注ConfigurationClassPostProcessor和AutowiredAnnotationBeanPostProcessor。

RootBeanDefinition的类结构图

spring源码解析(一)spring容器启动的十六个步骤_第6张图片

第二步:构造ClassPathBeanDefinitionScanner

在生成scanner的过程中,主要会注册几个默认的includeFilters:

  1. new AnnotationTypeFilter(Component.class)
  2. new AnnotationTypeFilter(ClassUtils.forName("javax.annotation.ManagedBean"))
  3. new AnnotationTypeFilter(ClassUtils.forName("javax.inject.Named"))

重点关注AnnotationTypeFilter(Component.class),它是用来判断一个类是不是应该被Spring扫描到的

 

第三步:注册自己的配置类到容器中:

spring源码解析(一)spring容器启动的十六个步骤_第7张图片

 

debug 发现:

spring源码解析(一)spring容器启动的十六个步骤_第8张图片

spring源码解析(一)spring容器启动的十六个步骤_第9张图片

从代码中可以看到,,是将我自己的mainconfig这个类的beandefiniton注册到bean工厂中。。。

 

 

最终我们来到了refresh方法,如下:

spring源码解析(一)spring容器启动的十六个步骤_第10张图片

第四步:用startupShutdownMonitor来加一把锁:用于“刷新”和“销毁”的同步监视器

第五步:调用prepareRefresh方法

为刷新准备新的上下文环境,设置其启动日期和活动标志以及执行一些属性的初始化。主要是一些准备工作,不是很重要的方法,可以先不关注。

 

第六步:调用obtainFreshBeanFactory方法

spring源码解析(一)spring容器启动的十六个步骤_第11张图片

用于获得一个新的 BeanFactory。

该方法会解析所有 Spring 配置文件(通常我们会放在 resources 目录下),将所有 Spring 配置文件中的 bean 定义封装成 BeanDefinition,加载到 BeanFactory 中。常见的,如果解析到 注解时,会扫描 base-package 指定的目录,将该目录下使用指定注解(@Controller、@Service、@Component、@Repository)的 bean 定义也同样封装成 BeanDefinition,加载到 BeanFactory 中。

这里 如果是xml中配置的bean,那么对应的beandefinition就是GenericBeanDefinition  而使用scan扫描到的注解的类对应的beandefinition就是 AnnotatedGenericBeanDefinition,AnnotatedGenericBeanDefinition 是GenericBeanDefinition 的扩展。。

从这里我们可以看出注解是xml的扩展机制。。。


上面提到的“加载到 BeanFactory 中”的内容主要指的是以下3个缓存:

beanDefinitionNames缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 集合。
beanDefinitionMap缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 和 BeanDefinition 映射。
aliasMap缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 和别名映射。

 

第七步:调用prepareBeanFactory(beanFactory) 方法

spring源码解析(一)spring容器启动的十六个步骤_第12张图片

配置 beanFactory 的标准上下文,例如上下文的 ClassLoader、后置处理器等。这个方法会注册3个默认环境 bean:environment、systemProperties 和 systemEnvironment,注册 2 个 bean 后置处理器:ApplicationContextAwareProcessor 和 ApplicationListenerDetector


第八步:调用postProcessBeanFactory(beanFactory) 方法

spring源码解析(一)spring容器启动的十六个步骤_第13张图片

这个方法允许子类对 BeanFactory 进行后续处理,默认实现为空,留给子类实现。

 

第九步:调用invokeBeanFactoryPostProcessors(beanFactory) 方法

spring源码解析(一)spring容器启动的十六个步骤_第14张图片

这里只截取了一部分代码。。。。

实例化和调用所有 BeanFactoryPostProcessor,包括其子类 BeanDefinitionRegistryPostProcessor。

BeanFactoryPostProcessor 接口是 Spring 初始化 BeanFactory 时对外暴露的扩展点,Spring IoC 容器允许 BeanFactoryPostProcessor 在容器实例化任何 bean 之前读取 bean 的定义,并可以修改它。

BeanDefinitionRegistryPostProcessor 继承自 BeanFactoryPostProcessor,比 BeanFactoryPostProcessor 具有更高的优先级,主要用来在常规的 BeanFactoryPostProcessor 激活之前注册一些 bean 定义。特别是,你可以通过 BeanDefinitionRegistryPostProcessor 来注册一些常规的 BeanFactoryPostProcessor,因为此时所有常规的 BeanFactoryPostProcessor 都还没开始被处理。 

这里的 “常规 BeanFactoryPostProcessor” 主要用来跟 BeanDefinitionRegistryPostProcessor 区分。

 

第十步:调用registerBeanPostProcessors(beanFactory) 方法

注册所有的 BeanPostProcessor,将所有实现了 BeanPostProcessor 接口的类加载到 BeanFactory 中。

BeanPostProcessor 接口是 Spring 初始化 bean 时对外暴露的扩展点,Spring IoC 容器允许 BeanPostProcessor 在容器初始化 bean 的前后,添加自己的逻辑处理。在这边只是注册到 BeanFactory 中,具体调用是在 bean 初始化的时候。

具体的:在所有 bean 实例化时,执行初始化方法前会调用所有 BeanPostProcessor 的 postProcessBeforeInitialization 方法,执行初始化方法后会调用所有 BeanPostProcessor 的 postProcessAfterInitialization 方法。

 

第十一步:调用initMessageSource() 方法

spring源码解析(一)spring容器启动的十六个步骤_第15张图片

初始化消息资源 MessageSource。
 

第十二步:调用initApplicationEventMulticaster() 方法

spring源码解析(一)spring容器启动的十六个步骤_第16张图片

初始化应用的事件广播器 ApplicationEventMulticaster 用来保存第十四步的listener

第十三步:调用onRefresh() 方法

spring源码解析(一)spring容器启动的十六个步骤_第17张图片

该方法为模板方法,提供给子类扩展实现,可以重写以添加特定于上下文的刷新工作,默认实现为空。

 

第十四步:调用registerListeners() 方法

spring源码解析(一)spring容器启动的十六个步骤_第18张图片

注册监听器。

 

第十五步:调用finishBeanFactoryInitialization(beanFactory) 方法

spring源码解析(一)spring容器启动的十六个步骤_第19张图片

这一步非常重要,,,也是spring的核心源码。。。。

该方法会实例化所有剩余的非懒加载单例 bean。除了一些内部的 bean、实现了 BeanFactoryPostProcessor 接口的 bean、实现了 BeanPostProcessor 接口的 bean,其他的非懒加载单例 bean 都会在这个方法中被实例化,并且 BeanPostProcessor 的触发也是在这个方法中。

1、遍历所有被加载到缓存中的 beanName,触发所有剩余的非懒加载单例 bean 的实例化。

2、首先通过 beanName 尝试从缓存中获取,如果存在则跳过实例化过程;否则,进行 bean 的实例化。

3、根据 BeanDefinition,使用构造函数创建 bean 实例。

4、根据 BeanDefinition,进行 bean 实例属性填充。

5、执行 bean 实例的初始化。

5.1、触发 Aware 方法。

5.2、触发 BeanPostProcessor 的 postProcessBeforeInitialization 方法。

5.3、如果 bean 实现了 InitializingBean 接口,则触发 afterPropertiesSet() 方法。

5.4、如果 bean 设置了 init-method 属性,则触发 init-method 指定的方法。

5.5、触发 BeanPostProcessor 的 postProcessAfterInitialization 方法。

6、将创建好的 bean 实例放到缓存中,用于之后使用。

 

第十六步:调用finishRefresh() 方法

spring源码解析(一)spring容器启动的十六个步骤_第20张图片

完成此上下文的刷新,主要是推送上下文刷新完毕事件(ContextRefreshedEvent )到监听器。

 

到此为止,,spring容器所有的启动过程已介绍完毕。。。。后续小编会逐个突破每一部分的源码。。。


 

 

 

 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(spring)