美文网首页Spring cloud
SpringApplication. run()的实现原理

SpringApplication. run()的实现原理

作者: 鸿雁长飞鱼龙潜跃 | 来源:发表于2019-06-24 18:28 被阅读57次

SpringApplication. run()的实现原理。

return new SpringApplication(sources).run(args);

一,SpringApplication初始化

return new SpringApplication(sources)

第一步:设置系统参数默认值。

this.bannerMode = Mode.CONSOLE;

this.logStartupInfo = true;

this.addCommandLineProperties = true;

this.headless = true;

this.registerShutdownHook = true;

第二步:设置初始化器。一共6个。

this.setInitializers();

第三步:设置监听器。一共13个。

this.setLisreners();

这些监听器会一直监听Spring项目的启动流程,每当Spring容器状态发生改变,就会出发响应的事件。

这里重点说一下这些监听器的加载逻辑。

首先,拿到当前类的类加载器。其实就是ApplicationClassLoader。

然后,去对应的文件中加载类。路径是META-INFO/spring.factories,这个路径相信大家不会陌生,如果我们想在Spring启动时加载我们自定义的Bean,那么我们就需要把Bean配置到这个文件中。

具体的加载实现可以参考SpringFactoryLoader,这个类实现的功能就是从META-INFO/spring.factories加载配置。

第四步:设置微服务启动类。启动入口。

this.mainApplicationClass = this.deduceMainApplicationClass();

加载启动类,会根据代码的堆栈调用关系,获取到StackTraceElement数组,然后根据main方法,找到main方法所在的class,这个class就是启动类。然后使用java反射机制加载启动类。

通常我们的微服务启动类是这样命名的:

XxxApplication.java

这是我们微服务的入口,就是在这个入口中调用SpringApplication.run来启动微服务的。

二,环境准备阶段


思考:bootstrap.properties如何加载到内存?

SpringApplication.run()执行的过程中会加载bootstrap.properties的配置项到内存。具体是执行下面这行代码来实现的:

ConfigurableEnvironment environment = this. prepareEnvironment(listeners,applicationArguments);

接下来,我们就分析一下这个环境变量的初始化流程。由于比较复杂,分步骤来说明。

prepareEnvironment(listeners,applicationArguments)方法进入以后。

第一步:this.getOrCreateEnvironment();

这行代码的功能就像它的名字,如果当前存在环境变量ConfigurableEnvironment,则直接返回。如果不存在,则新建,这里新建的是StandardServletEnvironment,然后强转成ConfigurableEnvironment返回。

StandardServletEnvironment继承了StandardEnvironment,主要包含4个系统属性:

servletConfigInitParams:断点调试无具体参数。

servletContextInitParams:断点调试无具体参数。

systemProperties:系统参数,59个。注意这59个参数,可以通过Java提供的System类直接获取到。如下:

System. getProperties("os.name");

systemEnvironment:系统参数,46个。

第二步:this.configEnvironment(environment,applicationArguments.getSourceArus())

这个没太看明白,对主流程影响不大,先略过。

第三步:listeners.environmentPrepared(environment)

这个步骤主要初始化5个属性:

bootstrap:这个属性主要是初始化spring.config.name,默认值bootstrap。

random:生成随机数,目前不知道干啥的。

applicationConfigurationProperties:解析微服务系统配置文件bootstrap.properties,解析以后生成的键值对就存放在这个对象中。

defaultProperties:这个属性有2个配置,

一个是spring. aop. proxyTargetClass,默认值为true,另一个是logging.pattern.level。

springCloudClientHostInfo:这个属性包含主机名和主机IP地址,对应的key分别为:spring.cloud.client.hostname和spring.cloud.client.ipAddress。

这一步的逻辑还是很复杂的,关键类是这个

SimpleApplicationEventMulticaster。使用的是事件机制,通过定时任务监听服务端的事件。

OK,环境准备阶段的工作基本就是这些。

最后我们来梳理一下环境准备阶段,初始化以后得到的环境对象,这个对象主要包含9个属性,就是上面分析的那9个属性:

servletConfigInitParams

servletContextInitParams

systemProperties

systemEnvironment

bootstrap

random

applicationConfigurationProperties

defaultProperties

springCloudClientHostInfo

初始化系统环境的本质,其实就是对这些系统变量,系统参数进行初始化。

三,打印横幅

代码如下:

Banner printedBanner = printBanner(environment);

这行代码的功能就是打印横幅。什么是横幅呢?就是我们启动微服务时,控制台那个经典的“spring”。这个横幅是支持自定义修改的,方法也很简单,只需要在resource目录下添加banner.txt即可,控制台会打印banner.txt中的内容。

四,创建IOC容器

// 依据是否为web环境创建web容器或者普通的IOC容器

context = createApplicationContext();

analyzers = new FailureAnalyzers(context);

这里说明一下,web容器指的是AnnotationConfigEmbeddedWebApplicationContext,IOC容器指的是AnnotationConfigApplicationContext。我们微服务是web环境,所以创建的是IOC容器。AnnotationConfigApplicationContext容器的主要功能就是Bean的注册,所有的Bean都在这里完成注册。

这里加载AnnotationConfigApplicationContext类,使用的是反射机制,最后生成对象后强转成ConfigurableApplicationContext返回。

这里我们也来看看最后生成的这个context的结构。

读取器:AnnotatedBeanDefinitionReader

扫描器:ClassPathBeanDefinitionScanner

Bean工厂:DefaultListableBeanFactory

其他的属性,这里不再赘述,我们只关注这3个重要的属性。读取器使用的依然是默认的AnnotatedBeanDefinitionReader,但是扫描器变成了ClassPathBeanDefinitionScanner,这个和注解扫描器AnnotatedBeanDefinitionScanner有所不同。Bean工厂依然是我们熟悉的DefaultListableBeanFactory,这里面有存放Bean的容器beanDefinitionMap及其他所有必要的容器和参数。

经过创建环境阶段以后,Spring完成了以下内容:

1,创建读取器。

2,创建扫描器。

3,创建Bean工厂。

4,创建其他IOC容器的必要参数和属性。

总之,我们的Spring容器启动了。

五,准备上下文阶段

prepareContext(context, environment, listeners, applicationArguments,

printedBanner);

这一步概括来说,就是把一些系统启动相关的Bean注册到IOC容器中。

第一步:

context. setEnvironment(environment);

在ConfigurableApplicationContext中设置环境environment,这里设置的environment就是我们环境准备阶段初始化的environment。

第二步:

this. postProcessApplicationContext(context);

注册Bean:internalConfigurationBeanNameGenerstor。

设置资源加载器resourceLoader和类加载器classLoader。

第三步:

listeners. contextPrepared(context);

通知监听器,上下文准备就绪。

第四步:注册Bean

springApplicationArguments

springBootBanner

第五步:加载系统Bean和项目XML配置文件。

第六步:

listeners. contextLoaded(context);

通知监听器,上下文加载完成。

第六步:刷新上下文

this.refreshContext(context);

刷新容器,完成组件的扫描,创建,加载等。刷新以后还会注册一个钩子registerShutdownHook,作用是在Spring容器关闭后执行一些操作。

第七步:注册一些定时任务、监听器状态同步、关闭计时器等

afterRefresh(context, applicationArguments);

listeners.finished(context, null);

通知监听器,Spring上下文启动完成。

stopWatch.stop();

关闭计时器。

return context;

返回Spring上下文,至此,SpringApplication.run()方法执行结束。

OK,啰啰嗦嗦一大堆,相信大家也也晕了,下面总结一下SpringApplication.run()的实现原理。

1,初始化SpringApplication。

设置一些系统参数,6个初始化器,13个监听器,设置main方法入口。

2,环境准备阶段。

初始化环境变量及其他系统参数,为启动做准备。这些参数有些是从jvm获取,有些是从项目的properties文件获取。

3,打印横幅。

4,创建IOC容器。

创建读取器。

创建扫描器。

创建Bean工厂。

创建其他IOC容器的必要参数和属性。

总之,Spring的IOC容器创建好了。

5,准备上下文阶段。

把之前准备的环境参数设置到IOC容器,并注册系统启动相关Bean到IOC容器。设置IOC容器的其他必要参数。

6,刷新上下文。

7,启动定时任务,监听器状态同步,关闭计时器。

纯手工断点调试写的,难免有疏漏,请大家多多指正。

相关文章

  • SpringApplication. run()的实现原理

    SpringApplication. run()的实现原理。 return new SpringApplicati...

  • 热修复实现原理(三)

    热修复实现原理——instant run 一、Instant Run 简介 Instant Run,是androi...

  • HandlerThread

    目录 什么是HandlerThread 实现原理run()getLooper()quit()quitSafely(...

  • iOS多线程的初步研究(四)-- NSTimer

    理解run loop后,才能彻底理解NSTimer的实现原理,也就是说NSTimer实际上依赖run loop实现...

  • 线程

    实现线程的方法 (1)继承Thread类,重写run方法。(2)实现Runnable接口,并实现该接口的run方法...

  • Instant Run 原理

    Instant Run,是android studio2.0新增的一个运行机制,在你编码开发、测试或debug的时...

  • 多线程,异常

    1.实现方式:继承Thread或实现Runable重写run()。 任务写在run()中,要实现线程行为,需要显示...

  • 十分钟掌握java多线程进阶

    一、线程的实现 继承thread类重写run()方法和实现Runnable接口实现run()方法 注意点:1、ne...

  • 线程池

    线程使用方法 继承Thread类,重写run()方法 实现Runnable接口,实现run()方法,在使用时,需要...

  • java线程

    一、线程创建方式 1.继承Thread类,重写run方法 2.实现Runnable接口,实现run方法 3.实现C...

网友评论

    本文标题:SpringApplication. run()的实现原理

    本文链接:https://www.haomeiwen.com/subject/zpnoqctx.html