SpringCloud启动源码分析

前言

​   在前面的博客中我们已经详细分析过Spring的启动源码,包括beanDefinition的加载、bean的初始化以及各种后处理器的回调,这个过程还是比较复杂的。

​   作为Spring全家桶中的一员,SpringCloud也是对Spring做的封装,底层逻辑其实一致,我们先来看看SpringCloud的入口方法:
在这里插入图片描述

​    我们直接去看看SpringApplicationrun方法,根据调用形式可以看到这里调用的是SpringApplication的静态run方法:

在这里插入图片描述

​   这部分的代码逻辑是:先创建一个SpringApplication对象,然后调用这个对象的的run方法。所以核心逻辑有两个部分:SpringApplication的构造方法和它的非静态run方法。

1. SpringApplication的构造方法

​   我们从源码可以看到,SpringApplication类没有继承任何类,也没有实现任何接口(我们在讲解Spring时,ClassPathXmlApplicationContext类图就非常复杂)。

在这里插入图片描述

​   我们接着来看看SpringApplication的构造方法,该构造方法的核心是调用getSpringFactoriesInstances方法,完成三个类型bean的实例化,注意这一步我们并未创建beanFactory:

在这里插入图片描述

​   这里完成了三个类型bean的实例化:BootstrapRegistryInitializerApplicationContextInitializerApplicationListener

​    我们接着看看getSpringFactoriesInstances方法,该方法核心逻辑有两个:

​   1.通过SpringFactoriesLoaderloadFactoryNames获得指定类型的类的全路径名;

​   2.通过createSpringFactoriesInstances创建实例;

在这里插入图片描述

​   getSpringFactoriesInstances首先会通过getClassLoader方法去获得类加载器:

在这里插入图片描述

​   类加载的一个作用是根据字节码文件创建Class对象,并保存在堆内存中。因此,创建一个对象是绕不开类加载器的,只不过大部分情况下是jvm帮我们完成了这些工作。

​   在获得类加载器后,会调用SpringFactoriesLoader的静态方法loadFactoryNames,该方法的作用是找到我们指定类的全路径名,有了类的全路径名才能加载Class对象并创建该类的对象,我们接着来看看loadFactoryNames方法:

在这里插入图片描述

​   loadFactoryNames的底层逻辑很好理解:通过静态方法loadSpringFactories找到所有第三方依赖包中的文件spring.factories的类的全路径名,然后进一步筛选出指定类型的全路径名并返回。

​   loadSpringFactories方法的底层逻辑是这样的:

1.根据类加载器查缓存(SpringFactoriesLoader的cache属性),结果不为空就直接返回;
2.结果为空,就去找有"META-INF/spring.factories"文件的第三方依赖包的路径;
3.遍历2中得到的路径,根据路径加载spring.factories文件中的全路径名;

在这里插入图片描述

在这里插入图片描述

4.遍历全路径名和实现类将其保存在result;
5.对result的value去重,并将value更改为不可修改的列表;
6.将入参classLoader作为key,result作为value,存入SpringFactoriesLoader的cache属性中。

在这里插入图片描述
在这里插入图片描述

​   当loadFactoryNames方法执行完成后,我们再回到getSpringFactoriesInstances方法:

在这里插入图片描述

​   接下来就是通过createSpringFactoriesInstances方法创建实例对象了,我们可以进到createSpringFactoriesInstances方法看看,其核心思想是通过反射创建对象:

在这里插入图片描述

​   以上就是getSpringFactoriesInstances方法的主要逻辑,总的来说就干了一件事,实例化指定类型的对象。让我们再回到SpringApplication的构造方法:

在这里插入图片描述

2.SpringApplication的非静态run方法

​   run方法会对SpringApplication继续做一些配置。

​   其中重要的是会创建一个上下文容器(类型为AnnotationConfigServletWebServerApplicationContext),就是我们Spring中讲过的上下文容器(类型为ClassPathXmlApplicationContext),二者类型有区别,但是也负责实例化bean:

在这里插入图片描述

​   之前讲解Spring容器的时候详细讲过refresh方法干了什么,虽然上下文容器的类型不同,但是处理的逻辑是大致相同,我们这里就简单介绍一下,不过多深入,首先我们来看看refreshContext方法:

在这里插入图片描述

​   最后还是调用到了AbstractApplicationContextrefresh方法,是不是很熟悉,没错就是ClassPathXmlApplicationContext调用的refresh方法,但是Spring Cloud在Spring基础上做了封装修改,refresh方法也有小改动,但是大体并没有变:

在这里插入图片描述

​   到了这一步,相信看了Spring源码文章的朋友们就非常熟悉了,这就是Spring启动的核心代码。

​   需要注意的有两点:

​   1.obtainFreshBeanFactory方法:在Spring中该方法会调用AbstractRefreshableApplicationContextrefreshBeanFactory方法,会完成beanDefinition加载。而在SpringCloud中,该方法会调用GenericApplicationContext中的refreshBeanFactory方法,该方法只设置了beanFactory的序列化id,并不会加载beanDefinition。

在这里插入图片描述

​   这里还有一个小细节需要注意一下,我们可以看到AbstractRefreshableApplicationContextrefreshBeanFactory方法会去创建一个beanFactory,那么SpringCloud是在哪创建beanFacotry的呢?

在这里插入图片描述

​   2.invokeBeanFactoryPostProcessors方法:在SpringCloud中该方法负责加载beanDefinition。其实SpringCloud对Spring做了进一步的封装体现在,SpringCloud自己定义了许多BeanFactoryPostProcessor类型的bean,SpringCloud自己负责注册这些bean,并让这些bean负责不同的功能。

​   我们也可以简单去看看invokeBeanFactoryPostProcessors方法:

在这里插入图片描述

​   我们可以进到invokeBeanFactoryPostProcessors方法内看看回调的逻辑:

在这里插入图片描述

​   我们再来看看此时容器中已经实例化的BeanFacoryPostProcessor类型的bean:

在这里插入图片描述

​   这三个类型的后处理器中,CachingMetadataReaderFactoryPostProcessorConfigurationWarningsPostProcessor都实现了BeanDefinitionRegistryPostProcessor接口,我们来看看它们的postProcessBeanDefinitionRegistry方法。

​   我们聚焦于核心流程,来看看CachingMetadataReaderFactoryPostProcessorpostProcessBeanDefinitionRegistry方法:

在这里插入图片描述

​   回调完后,我们继续回到invokeBeanFactoryPostProcessors方法中:

在这里插入图片描述

在这里插入图片描述

​   我们查看beanFactory中的beanDefinitionMap属性可以发现org.springframework.context.annotation.internalConfigurationAnnotationProcessor对应的bean为ConfigurationClassPostProcessor

在这里插入图片描述

​   接着继续回调ConfigurationClassPostProcessorpostProcessBeanDefinitionRegistry方法:

在这里插入图片描述

在这里插入图片描述

​   我们可以继续进到processConfigBeanDefinitions方法看看(这个方法巨长,我只截了关键代码):

在这里插入图片描述

在这里插入图片描述

​   所以在SpringCloud中,加载beanDefinition的主要工作是在ConfigurationClassPostProcessor中完成的。

小结

  本文主要内容是SpringCloud的启动流程源码分析,主要是聚焦于与Spring启动流程的差异性和特殊方面,有关Spring启动流程源码在之前的博客中已经有过讲解,因此就没有在本文中赘述。
  本文并未涉及SpringCloud服务发现和服务注册的源码,该部分会在后面的博客中更新(最近上班当牛马,狠狠干活,更新可能比较慢)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值