springboot启动过程
使用了很长时间的springboot了,一直都知道它简单易用,简化了框架的搭建过程,但是还是不知道它是如何启动的,今天就跟着springboot的源码,去探探这其中的奥妙
以下是spring应用的启动:
@SpringBootApplication
public class Application extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
//加载配置文件
System.setProperty("spring.config.location","classpath:db_config.properties,classpath:mq.properties");
SpringApplication.run(Application.class, args);
}
}
然后我们跟着Run方法进去
public ConfigurableApplicationContext run(String... args) {
//一开始就是一个StopWatch 类,这个类的主要作用是记录容器启动用时
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
Banner printedBanner = this.printBanner(environment);
context = this.createApplicationContext();
new FailureAnalyzers(context);
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
listeners.finished(context, (Throwable)null);
stopWatch.stop();
if(this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9);
throw new IllegalStateException(var9);
}
}
第一步:可以看到,一开始是一个StopWatch类,该类的作用比较单一,就是记录springboot的启动用时,我们启动springboot完成后会在控制台springboot启动所花的时间,就是由它来完成的
//然后我们看看this.createApplicationContext()方法:
private void configureHeadlessProperty() {
System.setProperty("java.awt.headless", System.getProperty("java.awt.headless", Boolean.toString(this.headless)));
}
//主要是用来设置系统属性,具体这个属性有何作用,有待探究
第二步:创建SpringApplicationRunListeners
//接下来我们看看springboot是如何去初始化监听器SpringApplicationRunListeners的。this.getRunListeners(args)方法如下:
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, new Object[]{this, args}));
}
//利用传入的参数args去创建一个SpringApplicationRunListeners实例,此处会去获取一个SpringFactory的实例,下面我们重点看看是如何来获取该SpringFactory实例的
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
//首先获取当前线程的类加载器,然后通过SpringFactoriesLoader去加载SpringApplicationRunListener这个类,接下来看看在加载SpringApplicationRunListener这个spring应用的运行监听器时做了什么事情
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
Enumeration ex = classLoader != null?classLoader.getResources("META-INF/spring.factories"):ClassLoader.getSystemResources("META-INF/spring.factories");
ArrayList result = new ArrayList();
while(ex.hasMoreElements()) {
URL url = (URL)ex.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
} catch (IOException var8) {
throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
}
}
//首先通过当前线程的类加载器获取Springboot项目META-INF下面的spring.factories文件,找到该文件,我们可以看到该文件中配置了PropertySource Loaders(属性来源加载)、运行监听器EventPublishingRunListener、运用上下文初始化工具、应用监听器等等一系列的自动化配置,都是从这里加载到应用中来的。加载完成之后,SpringFactory通过反射来获取这些类的实例,然后放入到SpringApplicationRunListeners中,至此,SpringApplicationRunListeners初始化完成。这里,我们看看SpringApplicationRunListeners中有些什么,源码如下:
class SpringApplicationRunListeners {
private final Log log;
private final List<SpringApplicationRunListener> listeners;
SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList(listeners);
}
}
//有一个log,用于记录日志,然后就是一个final的list,里面就是之前初始化时从配置中获取的各种listener
再次回顾一下SpringApplicationRunListeners的创建过程:首先获取当前线程的ClassLoader,然后通过SpringFactoriesLoader去加载Springboot项目中META-INF文件夹下的spring.factories配置文件,之后通过反射获取相关listener实例,存储到SpringApplicationRunListeners的list属性中,由此完成SpringApplicationRunListeners的初始化过程
第三步:启动SpringApplicationRunListeners中所有的监听器
第四步:环境准备
第五步:打印Banner
第六步:创建上下文
springboot启动过程的更多相关文章
- SpringBoot启动过程原理
最近这两年springboot突然火起来了,那么我们就来看看springboot的运行原理. 一.springboot的三种启动方式: 1.运行带有main方法的2.通过命令 Java -jar命令3 ...
- Spring Boot 学习笔记一(SpringBoot启动过程)
SpringBoot启动 Spring Boot通常有一个名为*Application的入口类,在入口类里有一个main方法,这个main方法其实就是一个标准的java应用的入口方法. 在main方法 ...
- (四)SpringBoot启动过程的分析-预处理ApplicationContext
-- 以下内容均基于2.1.8.RELEASE版本 紧接着上一篇(三)SpringBoot启动过程的分析-创建应用程序上下文,本文将分析上下文创建完毕之后的下一步操作:预处理上下文容器. 预处理上下文 ...
- (三)SpringBoot启动过程的分析-创建应用程序上下文
-- 以下内容均基于2.1.8.RELEASE版本 紧接着上一篇(二)SpringBoot启动过程的分析-环境信息准备,本文将分析环境准备完毕之后的下一步操作:ApplicationContext的创 ...
- (一)SpringBoot启动过程的分析-启动流程概览
-- 以下内容均基于2.1.8.RELEASE版本 通过粗粒度的分析SpringBoot启动过程中执行的主要操作,可以很容易划分它的大流程,每个流程只关注重要操作为后续深入学习建立一个大纲. 官方示例 ...
- (五)SpringBoot启动过程的分析-刷新ApplicationContext
-- 以下内容均基于2.1.8.RELEASE版本 紧接着上一篇[(四)SpringBoot启动过程的分析-预处理ApplicationContext] (https://www.cnblogs.co ...
- springboot启动过程(1)-初始化
1 springboot启动时,只需要调用一个类前面加了@SpringBootApplication的main函数,执行SpringApplication.run(DemoApplication. ...
- SpringBoot启动过程原理(转)
1.1 Springboot启动: @SpringBootApplication public class ServerApplication { public static void main(St ...
- (二)SpringBoot启动过程的分析-环境信息准备
-- 以下内容均基于2.1.8.RELEASE版本 由上一篇SpringBoot基本启动过程的分析可以发现在run方法内部启动SpringBoot应用时采用多个步骤来实现,本文记录启动的第二个环节:环 ...
随机推荐
- 秒懂神经网络---BP神经网络具体应用不能说的秘密.
秒懂神经网络---BP神经网络具体应用不能说的秘密 一.总结 一句话总结: 还是要上课和自己找书找博客学习相结合,这样学习效果才好,不能单视频,也不能单书 BP神经网络就是反向传播神经网络 1.BP神 ...
- fedora 18~20 中Qt 5.2.1 解决连接mysql数据库出现QMYSQL driver not loaded的问题
QT += sql //在.pro文件里加入这一句 //包含头文件 #include <QDebug> #include <QSqlQuery> #include ...
- 什么是css块级元素和内联元素
CSS文档流与块级元素(block).内联元素(inline),文档流这个概念理解了它,一堆CSS布局的理论都 变得易于理解,并且体会到CSS这套设计的合理性所在. 文档流 将窗体自上而下分成一行行, ...
- webpack3
6月20号webpack推出了3.0版本,官方也发布了公告.根据公告介绍,webpack团队将未来版本的改动聚焦在社区提出的功能需求,同时将保持一个快速.稳定的发布节奏.本文主要依据公告内容,简单介绍 ...
- 牛客B-Xor Path /// 求所有Path( i->j )( j >= i )路径的异或和
题目大意: https://ac.nowcoder.com/acm/contest/272/B?&headNav=acm 给定一棵n个点的树,每个点有权值.定义表示 到 的最短路径上,所有 ...
- java_函数式编程写法
package cn.aikang.Test; import org.junit.Test; import java.util.Scanner; import java.util.function.S ...
- sql 循环执行游标
---定义开始和结束时间 declare @st_dt datetime declare @en_dt datetime ---时间赋值 ' ' ---定义中间变量 declare @dt datet ...
- 威布尔weibull distribution
data = wblrnd(0.5,0.8,100,1); 生成威布尔随机函数,尺寸参数为0.5,形状参数为0.8,生成数列100行,一列: parmhat = wblfit(data) 对data的 ...
- [JZOJ3235] 数字八
题目 题目大意 给你一个二维的图,其中.代表完好,*代表有缺陷. 现在要在图上刻一个数字\(8\),满足: 由两个矩形组成. 每个矩形中必须有空隙在内部,也就是说,至少为\(3*3\)的矩形. 上矩形 ...
- 【JZOJ6376】樱符[完全墨染的樱花]
description analysis 无向图上任意两点最大流不超过\(2\),说明该图是仙人掌 由于最大流等于最小割,如果一条边在两个环里,断掉两个端点至少需要\(3\)的代价 对于该仙人掌,求两 ...