序言
本人为初学者,对SpringBoot源码的理解尚浅,若笔记有误,欢迎各位读者指正;
概述
在初步的探讨中,先通过debug从全局简单了解一下springboot启动的配置及作用;
长话短说,直接进入正题,通过源码探讨SpringBoot的启动流程;
启动点:
@SpringBootApplication
public class DormitoryApplication {
public static void main(String[] args) {
SpringApplication.run(DormitoryApplication.class, args);
}
}
进入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) {
//时间监控器,可以记录总的运行时间和对应的每个task的运行时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//listeners是一个监听器的容器,监听容器的创建过程并打印日志,在监听器容器中有11个监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
//applicationArgument 是允许application Context的参数类
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
//配置欲忽视的bean信息
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//通过debug日志猜想这个函数只会扫描到application.yml的配置文件
refreshContext(context);
//容器开始扫描项目中的bean文件并添加到bean容器中,context中有一个bean factory,已注册的bean会在这里定义
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
通过run方法前的英文注释可以得知,run 方法的作用是启动一个SpringBoot Application, 创建一个Spring容器,并且将springContext 进行返回;
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
listeners是一个监听器的容器,监听容器的创建过程并打印日志,在监听器容器中有11个监听器,如下图所示:
通过debug日志猜想这个函数只会扫描到application.yml的配置文件,输出日志如下:
refreshContext(context);
2020-04-30 18:06:50.950 INFO 24196 --- [ main] com.myBaties.DormitoryApplication : Starting DormitoryApplication on zhenghaojiadeMacBook-Pro.local with PID 24196 (/Users/zhenghaojia/IdeaProjects/myBaties/target/classes started by zhenghaojia in /Users/zhenghaojia/IdeaProjects/myBaties)
2020-04-30 18:06:50.967 INFO 24196 --- [ main] com.myBaties.DormitoryApplication : The following profiles are active: dev
在以下的方法中,容器开始扫描项目中的bean文件并添加到bean容器中,context中有一个bean factory,已注册的bean会在这里定义;
afterRefresh(context, applicationArguments);
总结
通过debug, 尚未深入逻辑代码,可以了解到SpringBoot简单的启动流程;
1、框架启动运行的时候,会先启动一个时间监控器,监控器可以记录总任务及各个任务的运行时间; => stopWatch.start();
2、接着初始化并启动监听器 => listeners.starting();
3、配置好Context的运行环境 => prepareContext(context, environment, listeners, applicationArguments, printedBanner);
4、读取配置文件 => refreshContext();
5、加载Bean到bean工厂中 => afterRefresh(context, applicationArguments);