Spring Boot启动过程分析
以一个web工程启动为例, maven中引入
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
示例启动类:
package com.simple.boot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * @author LILE */ @SpringBootApplication public class SimpleBootApplication { public static void main(String[] args) { SpringApplication.run(SimpleBootApplication.class); } }
SpringApplication.run是调用静态run方法启动, 内部会创建SpringApplication实例, 并通过实例调用非静态run方法, run方法有几种重载形式, 我们只关注最终的调用:
new SpringApplication(sources).run(args)
SpringApplication是SpringBoot程序的入口, 启动SpringBoot首先会实例化SpringApplication对象, SpringApplication最重要的功能是创建并初始化AppliactionContext, 下面就分别分析new SpringApplication和run方法
一、 new SpringApplication(sources):
Tips: sources参数就是[SimpleBootApplication.class]
SpringApplication用于启动一个SpringBoot程序, 它允许我们自定义ApplicationContextInitializer 和ApplicationListener, 用于在SpringBoot启动时的不同阶段, 执行自定义代码, 而SpringApplication的构造器中, 主要就负责读取并实例化这些监听对象。
SpringApplication构造器主要逻辑代码(均位于SpringApplication.java):
248:this.webEnvironment = deduceWebEnvironment(); // 判断是否是WEB环境, 返回boolean值, "javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext", 看这两个类信息是否能加载到 249:setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); // 设置this.initializers, 均实现ApplicationContextInitializer接口 251:setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 设置this.listeners, 均实现ApplicationListener接口 252:this.mainApplicationClass = deduceMainApplicationClass(); // 找到main方法对应的类, 这里是SimpleBootApplication.class
249、251都是调用 getSpringFactoriesInstances, 该方法作用如下:
1、从类路径的 META-INF/spring.factories文件加载所有类定义
2、按类型条件过滤出指定Class定义, 如249过滤出ApplicationContextInitializer实现类, 251过滤出ApplicationListener实现类
3、实例化这些类, BeanUtils.instantiateClass
4、对实例排序 AnnotationAwareOrderComparator.sort(instances);
new SpringApplication的主要逻辑就执行完成了, 可以通过断点, 看下最终值:
this.sources = [SimpleBootApplication.class]; this.webEnvironment = true; // ApplicationContext初始化实现类, 在run方法中会被调用 this.initializers = [ 0 = {DelegatingApplicationContextInitializer@1109} 1 = {ContextIdApplicationContextInitializer@1110} 2 = {ConfigurationWarningsApplicationContextInitializer@1111} 3 = {ServerPortInfoApplicationContextInitializer@1112} 4 = {SharedMetadataReaderFactoryContextInitializer@1113} 5 = {AutoConfigurationReportLoggingInitializer@1114} ]; // 监听器, 在run方法中会被调用 this.listeners = [ 0 = {ConfigFileApplicationListener@1098} 1 = {AnsiOutputApplicationListener@1099} 2 = {LoggingApplicationListener@1100} 3 = {ClasspathLoggingApplicationListener@1101} 4 = {BackgroundPreinitializer@1102} 5 = {DelegatingApplicationListener@1103} 6 = {ParentContextCloserApplicationListener@1104} 7 = {ClearCachesApplicationListener@1105} 8 = {FileEncodingApplicationListener@1106} 9 = {LiquibaseServiceLocatorApplicationListener@1107} ]; // 主函数所在的类 this.mainApplicationClass = SimpleBootApplication.class;
这些initializers, listeners将在run方法中, 不同的时机调用。
二、run(args) :
run方法的执行逻辑几乎都是围绕着ApplicationContext, 从ApplicationContext预处理、创建、完成创建:
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; FailureAnalyzers analyzers = null; configureHeadlessProperty(); 291:SpringApplicationRunListeners listeners = getRunListeners(args); 292:listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); 296:ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); 298:Banner printedBanner = printBanner(environment); 299:context = createApplicationContext(); analyzers = new FailureAnalyzers(context); 301:prepareContext(context, environment, listeners, applicationArguments, printedBanner); 303:refreshContext(context); 304:afterRefresh(context, applicationArguments); 305:listeners.finished(context, null); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } return context; } catch (Throwable ex) { handleRunFailure(context, listeners, analyzers, ex); throw new IllegalStateException(ex); } }