springboot的启动源码流程(菜鸟笔记)
程序员文章站
2024-03-26 13:51:05
...
springboot的启动源码流程
1.几个重要的事件回调机制
//放在类路劲下的META-INF/spring.factories文件中
ApplicationContextInitializer
ApplicationListener
//先执行ApplicationRunner,再执行CommandLineRunner
ApplicationRunner
CommandLineRunner
2.springboot.run(Main.class)分为两部分
//首先spring容器的创建
//执行容器的run方法
new SpringApplication(primarySources).run(args);
3.spring容器的创建
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//保存主配置类
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//判断是否是web应用
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//从类路劲下找到\META-INF\spring.factories配置所有的ApplicationContextInitializer然后保存起来
//getSpringFactoriesInstances
//1.从META-INF/spring.factories文件中找实现了ApplicationContextInitializer接口的所有类
//1.1 实现类如下
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
//2.createSpringFactoriesInstances 获取到的全类名,通过反射创建实例
//3.保存ApplicationContextInitializer创建的实例
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//从类路劲下找到\META-INF\spring.factories配置所有实现了ApplicationListener接口的类
//getSpringFactoriesInstances
//1.从META-INF/spring.factories文件中找实现了ApplicationListener接口的所有类
//1.1 实现类如下:
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
//2.createSpringFactoriesInstances 获取到的全类名,通过反射创建实例
//3.保存ApplicationListener创建的实例
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//从配置类中找到有main方法的主类
this.mainApplicationClass = deduceMainApplicationClass();
}
4.执行容器的run方法
/**
* Run the Spring application, creating and refreshing a new ApplicationContext
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
//用来打印,方法执行的时间,
//如:Started BootMasterApplication in 56.783 seconds (JVM running for 69.93)
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//1.申明ioc容器
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
//2.配置环境变量 java.awt.headless='true'
configureHeadlessProperty();
//3.在\META-INF\spring.factories中找实现类接口SpringApplicationRunListener的所有类,并依次创建类的实例
SpringApplicationRunListeners listeners = getRunListeners(args);
//4.回调SpringApplicationRunListener.starting();依次开启所有的监听器
listeners.starting();
try {
//5.包装传入参数 在Idea工具中添加命令行参数,如username=zzhua password=1234
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//6.准备环境变量
//6.1 获取或者创建环境,配置环境
//6.2 回调SpringApplicationRunListener.environmentPrepared(environment);表示环境准备完成
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
//6.3 配置ignore 的Bean信息
configureIgnoreBeanInfo(environment);
//7.打印Banner
Banner printedBanner = printBanner(environment);
//8.创建ApplicationContext,决定创建web容器还是普通的ioc,反射技术
context = createApplicationContext();
//9.异常信息处理
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//10.准备上下文环境
//10.1 将environment保存到ioc容器中
//10.2 applyInitializers(),回调前面保存的所有的ApplicationContextInitializer实现类的initialize()方法
//10.3 回调所有的SpringApplicationRunListener.contextPrepared()
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//11. spring容器的刷新 applicationContext).refresh(); 【如果是web应用还会创建嵌入式的Tomcat】。 其他章节已经整理
refreshContext(context);
//空方法,让子类实现
afterRefresh(context, applicationArguments);
//12.监控结束,并打印花费时间日志
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
//13.所有的SpringApplicationRunListener回调started()方法,表示容器开启完成
listeners.started(context);
//14
//14.1 在ioc容器中获取所有实现了ApplicationRunner和CommandLineRunner接口的类
//14.2 先回调所有的ApplicationRunner.run()
//14.3 再回调所有的CommandLineRunner.run()
callRunners(context, applicationArguments);
}catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
//回调SpringApplicationRunListener.running()
listeners.running(context);
}catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
//返回创建好的容器
return context;
}
推荐阅读
-
SpringBoot中启动Tomcat的步骤流程
-
springboot的启动源码流程(菜鸟笔记)
-
SpringBoot启动流程的简析
-
springboot 的启动流程(一)
-
Android Service的启动流程源码分析
-
ROS源码研究(二):命令roscore执行流程及添加开机自动启动的节点(类似/rosout)
-
Springboot 的一些基础源码分析 (一)SpringApplication执行流程
-
SpringBoot内置tomcat启动原理、以及SpringBoot初始化Servlet的源码分析
-
Hadoop源码学习笔记之NameNode启动流程分析一:源码环境搭建和项目模块及NameNode结构简单介绍
-
Android okhttp的启动流程及源码解析