springboot启动过程(2)-run方法
1 springApplication的run
run方法主要是用于创造spring容器ConfigurableApplicationContext对象。
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch(); // 构造一个任务执行观察器
stopWatch.start(); // 开始执行,记录开始时间
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
// 获取SpringApplicationRunListeners,内部只有一个EventPublishingRunListener
SpringApplicationRunListeners listeners = getRunListeners(args);
// 会封装成SpringApplicationEvent事件然后广播出去给SpringApplication中的listeners所监听
// 这里接受ApplicationStartedEvent事件的listener会执行相应的操作
listeners.started();
try {
// 构造一个应用程序参数持有类
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//创建并配置环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
//输出banner
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, ex); // 这个过程报错的话会执行一些异常操作、然后广播出ApplicationFailedEvent事件给相应的监听器执行
throw new IllegalStateException(ex);
}
}
2 run的过程
按顺序看run,发现执行了下面这些过程。
(1 )stopWatch 记录开始结束时间,configureHeadlessProperty 设置headless模式,awt的headless,一般运行在服务器端,在没有显示器和鼠标键盘的模式下工作,模拟输入输出设备功能。
(2)springApplicationListeners: 这个类包含了SpringApplicationRunlistener的集合和一个日志类。SpringApplicationRunlistener也是通过spring.factories加载,如下可以看到,就包含一种EventPublishingRunListener。
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
EventPublishingRunListener通过看源码,发现包含了started environmentPrepared contextPrepared contextLoaded等方法,基本都是包装特定event并发event。配合run函数的代码如下,可以得知,springApplicationListeners主要负责在run函数的各个阶段,发起事件。比如在创建spring容器的前后调用了start和finish方法,在创建容器时,把listener当参数传入便于在各个时间发起事件。
(3)prepareEnvironment 创建并设置环境
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
listeners.environmentPrepared(environment);
if (isWebEnvironment(environment) && !this.webEnvironment) {
environment = convertToStandardEnvironment(environment);
}
return environment;
}
如上,设置环境分几个步骤,getOrderCreateEnvironment获得一个标准环境对象StandardEnvironment,然后configureEnvironment进行配置。其中configureEnvironment 包含两个配置,configurePropertySources和configureProfiles两个方法。Environment代表程序运行环境,包含两种信息,一个是profiles,描述各种bean defination,另一种是properties描述系统配置,包括配置文件 jvm属性文件 环境变量等。configureEnvironment方法先是调用configurePropertySources来配置properties,然后调用configureProfiles来配置profiles。然后listener发出事件。
(4)pringBnner 打印banner,打印banner信息,即启动时出现的logo信息。
(5)createApplicationContext 创建spring容器。如果是web程序,那么构造org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext容器,否则构造org.springframework.context.annotation.AnnotationConfigApplicationContext容器
(6)prepareContext 首先调用了postProcessApplicationContext(context),如果是web程序并且是spring web容器,那么设置实例命名生成器并注册,同时注册资源加载器并注册。然后调用applyInitializers(context),遍历每个初始化器,调用相应的innitialize方法让初始化器开始工作。
(7)refreshContext(context) 刷新spring容器,内部做很多事情,包括springFactory设置,BeanFactoryPostProcessor接口执行,BeanPostProcessor接口执行,自动化配置类解析,条件注解解析,国际化的初始化等。
(8)afterRefresh 调用了 callRunners,主要是得到所有的CommonandLineRunner和ApplicationRunner, 使用 @Order(value=x)设置排序值,可以支持自定义runner完成自己需求。
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<Object>();
// 找出Spring容器中ApplicationRunner接口的实现类
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
// 找出Spring容器中CommandLineRunner接口的实现类
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
// 对runners进行排序
AnnotationAwareOrderComparator.sort(runners);
// 遍历runners依次执行
for (Object runner : new LinkedHashSet<Object>(runners)) {
if (runner instanceof ApplicationRunner) { // 如果是ApplicationRunner,进行ApplicationRunner的run方法调用
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) { // 如果是CommandLineRunner,进行CommandLineRunner的run方法调用
callRunner((CommandLineRunner) runner, args);
}
}
}
springboot启动过程(2)-run方法的更多相关文章
- 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启动过程中执行的主要操作,可以很容易划分它的大流程,每个流程只关注重要操作为后续深入学习建立一个大纲. 官方示例 ...
- (五)SpringBoot启动过程的分析-刷新ApplicationContext
-- 以下内容均基于2.1.8.RELEASE版本 紧接着上一篇[(四)SpringBoot启动过程的分析-预处理ApplicationContext] (https://www.cnblogs.co ...
- (三)SpringBoot启动过程的分析-创建应用程序上下文
-- 以下内容均基于2.1.8.RELEASE版本 紧接着上一篇(二)SpringBoot启动过程的分析-环境信息准备,本文将分析环境准备完毕之后的下一步操作:ApplicationContext的创 ...
- springboot启动过程(3)-refresh方法
1 springboot在启动的时候,会调用run方法,创建环境设置spring容器,其中包含refresh方法,完成配置类解析,各种beanFactoryPostProcess和beanPostP ...
- springboot启动过程(1)-初始化
1 springboot启动时,只需要调用一个类前面加了@SpringBootApplication的main函数,执行SpringApplication.run(DemoApplication. ...
- SpringBoot启动过程原理(转)
1.1 Springboot启动: @SpringBootApplication public class ServerApplication { public static void main(St ...
随机推荐
- WebServers 异步
在网上也找了一些,发现要么题目和内容不对应,明明是在Winform下异步调用,却写成在Asp.net异步调用WebService,有的调用方式在.NET3.5下不能通过,.NET3.5下取消了Begi ...
- 31 python下实现并发编程
一 背景知识 顾名思义,进程即正在执行的一个过程.进程是对正在运行程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操作系统的其他所 ...
- 20180907_网络差_天安微信token请求超时
一.异常现象 token请求时,显示请求超时. 二.原因分析 这个异常有如下几个原因: (1)服务器没有开通 qyapi.weixin.qq.com 的外网权限 (2)服务器网络太慢 三.异常解决 ...
- 在Java中定义常量
方法一采用接口(Interface)的中变量默认为static final的特性. 方法二采用了Java 5.0中引入的Enum类型. 方法三采用了在普通类中使用static final修饰变量的方法 ...
- XML DOM - Range 对象
Range对象 Range对象表示文档的连续范围区域,如用户在浏览器窗口中用鼠标拖动选中的区域. dom标准Range对象 在IE中使用TextRange对象 range对象常用的建立方法在开发中 ...
- SQL-主键与外键
1.PRIMARY KEY 主键,唯一标识一行或多行,不允许重复值,也不允许未NULL. 语法:[CONSTRAINT <约束名>] PRIMARY KEY [(列名1,列名2...)] ...
- PHP Smarty template for website
/****************************************************************************** * PHP Smarty templat ...
- LightOJ 1224 DNA Prefix
Given a set of n DNA samples, where each sample is a string containing characters from {A, C, G, T}, ...
- ACM学习历程—HDU5666 Segment(数论)
http://acm.hdu.edu.cn/showproblem.php?pid=5666 这题的关键是q为质数,不妨设线段上点(x0, y0),则x0+y0=q. 那么直线方程则为y = y0/x ...
- 洛谷 P3048 [USACO12FEB]牛的IDCow IDs
题目描述 Being a secret computer geek, Farmer John labels all of his cows with binary numbers. However, ...