博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringBoot(2)—启动原理之run方法的运行
阅读量:4030 次
发布时间:2019-05-24

本文共 6974 字,大约阅读时间需要 23 分钟。

SpringBoot版本为:2.1.1.RELEASE

在上一篇文章中,我们讲到了SpringApplication对象的创建,接下来将会分析SpringApplication创建之后run()方法的执行。

通过debug的方式,我们可以进入run方法,源代码如下:

/**	 * Run the Spring application, creating and refreshing a new	 * {@link ApplicationContext}.	 * @param args the application arguments (usually passed from a Java main method)	 * @return a running {@link ApplicationContext}	 */	public ConfigurableApplicationContext run(String... args) {
<1>: StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection
exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); <2>: SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try {
<3>: ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); <4>: ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); <5>: Banner printedBanner = printBanner(environment); <6>: context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] {
ConfigurableApplicationContext.class }, context); <7>: prepareContext(context, environment, listeners, applicationArguments, printedBanner); <8>: refreshContext(context); <9>: afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } <10>: listeners.started(context); <11>: callRunners(context, applicationArguments); } catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try {
<12>: listeners.running(context); } catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } <13>: return context; }

下面我们逐一分析:

<1> : StopWatch stopWatch = new StopWatch();
stopWatch.start();

这段代码功能很简单,创建一个StopWatch对象,开始记录run()启动过程时长;

<2>: 先来看这个方法:SpringApplicationRunListeners listeners = getRunListeners(args);

private SpringApplicationRunListeners getRunListeners(String[] args) {
Class
[] types = new Class
[] {
SpringApplication.class, String[].class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)); }

在这段代码里,我们又看见了熟悉的 getSpringFactoriesInstances(),原理还是一样,就是 getSpringFactoriesInstances()方法会从类路径下的 META-INF/spring.factories文件中找 对应SpringApplicationRunListener的全路径数组,并通过createSpringFactoriesInstances()方法实例化成对象返回;

再看 listeners.starting() 方法:

public void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting(); } }

所以这个方法就是回调之前获得的所有SpringApplicationRunListener对象的starting()方法,启动监听。我们可以继续再深入看一下这个监听对象的其他方法:

在这里插入图片描述

SpringApplicationRunListener 接口中共有上面几个方法,这几个方法将会贯穿run()方法的运行。

<3>:这个方法的作用也很简单,即使封装命令行参数。

<4>: ConfigurableEnvironment environment = prepareEnvironment(listeners,

applicationArguments)

其实这是环境准备阶段,我们可以看一下它的实现过程:

private ConfigurableEnvironment prepareEnvironment(			SpringApplicationRunListeners listeners,			ApplicationArguments applicationArguments) {
// Create and configure the environment ConfigurableEnvironment environment = getOrCreateEnvironment(); configureEnvironment(environment, applicationArguments.getSourceArgs()); listeners.environmentPrepared(environment); bindToSpringApplication(environment); if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()) .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } ConfigurationPropertySources.attach(environment); return environment; }

这个方法表示创建环境,并且environment 的属性都会加载进来,包括 application.properties 和外部的属性配置,具体实现有兴趣的同学可以研究一下。其中listeners.environmentPrepared(environment)方法表示环境准备完成

<5>:功能为打印Banner,也可以自定义启动logo,比如在resources路径下创建一个banner.txt文件,将你想打印的图标放入其中

<6>:创建ApplicationContext容器,根据类型决定是创建普通WEB容器还是REACTIVE容器还是普通Annotation的ioc 容器

<7>:prepareContext(context, environment, listeners, applicationArguments,

printedBanner);
这个方法的具体实现:

private void prepareContext(ConfigurableApplicationContext context,			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,			ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment); postProcessApplicationContext(context); 7.1: applyInitializers(context); 7.2: listeners.contextPrepared(context); if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner); } if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } // Load the sources Set sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); load(context, sources.toArray(new Object[0])); listeners.contextLoaded(context); }

7.1: 从initializers集合中遍历所有的ApplicationContextInitializer,并通过initializer.initialize( )方法初始化

7,2:回调SpringApplicationRunListener对象的contextPrepared()方法,表示容器已准备

<8>:refreshContext(context)

刷新容器,初始化ioc容器,向容器中加入配置类、组件,并且可以出发自动配置功能,具体原理可以参考SpringBoot的自动配置原理和Spring注解版容器的加载

<9>: afterRefresh(context, applicationArguments);

执行Spring容器初始化的后置处理,默认为空

protected void afterRefresh(ConfigurableApplicationContext context,			ApplicationArguments args) {
}

<10>: listeners.started(context);

回调所有的SpringApplicationRunListener对象的started()方法

<11>: callRunners(context, applicationArguments)

private void callRunners(ApplicationContext context, ApplicationArguments args) {
List runners = new ArrayList<>(); runners.addAll(context.getBeansOfType(ApplicationRunner.class).values()); runners.addAll(context.getBeansOfType(CommandLineRunner.class).values()); AnnotationAwareOrderComparator.sort(runners); for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args); } if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args); } } }

调用ApplicationRunner或者CommandLineRunner 的运行方法,其中ApplicationRunner的优先级要比CommandLineRunner要高。

在我们日常的项目里,经常需要初始化一些资源,比如线程池或者数据库数据等,我们就可以实现这两个接口,在实现方法里写具体的处理逻辑,也可以在实现类上加上@Order(value) 注解来指定优先级(ps:该实现类要加上@Component)

<12>:listeners.running(context);

回调所有SpringApplicationRunListener对象的running()方法

<13>:return context

返回容器

至此,SpringBoot的启动过程已全部完毕,下一篇文章将会讲解SpringBoot的事件监听机制!

转载地址:http://aqmbi.baihongyu.com/

你可能感兴趣的文章
GNU hello代码分析
查看>>
Qt继电器控制板代码
查看>>
busybox passwd修改密码
查看>>
wpa_supplicant控制脚本
查看>>
rfkill: WLAN hard blocked
查看>>
gstreamer相关工具集合
查看>>
arm 自动升级脚本
查看>>
RS232 四入四出模块控制代码
查看>>
gstreamer插件之 videotestsrc
查看>>
autoupdate script
查看>>
linux 驱动开发 头文件
查看>>
/etc/resolv.conf
查看>>
container_of()传入结构体中的成员,返回该结构体的首地址
查看>>
linux sfdisk partition
查看>>
ipconfig,ifconfig,iwconfig
查看>>
opensuse12.2 PL2303 minicom
查看>>
电平触发方式和边沿触发的区别
查看>>
网络视频服务器移植
查看>>
Encoding Schemes
查看>>
移植QT
查看>>