SpringBoot啟動流程總結
1.導語
//以下是一個SpringBoot應用的標準入口:
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
//SpringApplication.run 內部是這樣的:先創建一個 SpringApplication 對象,然后調用他的run方法。
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
所以想要了解清楚 SpringBoot 啟動流程,相當于了解 SpringApplication 的 構造方法 和 run方法。
2.構造方法詳解
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 判斷應用類型,會有三種情況:
// NONE:非web應用
// SERVLET:普通web應用
// REACTIVE:響應式web應用
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 從 META-INF/spring.factories 文件中獲取如下內容
// 獲取 注冊初始化器:在 run 方法中的 createBootstrapContext(); 里會被使用
this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
// 獲取 容器初始化器:在 run 方法中的 prepareContext( ... ); 里會被使用
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 獲取 監聽器:在 run 方法中 listeners.xxx 時被使用
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
3.run方法詳解
public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
// 第一步:創建監聽器
SpringApplicationRunListeners listeners = getRunListeners(args);
// 發布事件:開始啟動
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 第二步:準備環境變量
// 把一系列設置整合成 environment,包括 系統變量、JVM參數、啟動參數(args)、配置文件(application、bootstrap等)
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
Banner printedBanner = printBanner(environment);
// 第三步:創建空容器
// 根據 new 時判斷的 web類型(webApplicationType),創建對應類型的容器
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
// 第四步:準備容器
// 把前面準備的東西注入進去,包括 環境變量(environment)、事件監聽器(listeners)、啟動參數(applicationArguments)
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 第五步:啟用容器
// 解析@SpringBootApplication注解,加載自動配置類
// 進行Bean的掃描、加載、實例化、依賴注入
// 如果是Web應用,會啟動一個內嵌式的Web服務器比如Tomcat
refreshContext(context);
// 容器初始化后的操作,是個空方法,要使用需要繼承并重寫
afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
// 發布事件:已啟動
listeners.started(context, timeTakenToStartup);
// 執行啟動后的自定方法:
// 實現 ApplicationRunner、CommandLineRunner 接口
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
if (ex instanceof AbandonedRunException) {
throw ex;
}
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
// 檢查應用是否還在運行
if (context.isRunning()) {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
// 發布事件:準備就緒
listeners.ready(context, timeTakenToReady);
}
}
catch (Throwable ex) {
if (ex instanceof AbandonedRunException) {
throw ex;
}
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
// 返回Bean容器
return context;
}
浙公網安備 33010602011771號