知識儲備:SpringBoot啟動執行流程原理解析
SpringBoot專案通過SpringApplication.run()執行,分為兩步
首先new了一個SpringApplication,之後再呼叫run()方法 ,下面我們就看看這兩步
1.建立SpringApplication
通過debug進入到SpringApplication的建立中
首先判斷當前專案是否是web專案,再在所有jar包的META-INF/spring.factories檔案中查詢ApplicationContextInitializer和ApplicationListener並儲存,之後再通過所有配置類獲得帶有main方法的主執行類
獲得的所有ApplicationContextInitializer型別
獲得所有的ApplicationListener型別,到這裡SpringApplication就建立完成
2.呼叫run()方法
通過debug進入其中
在這裡首先通過spring.factories檔案獲得所有SpringApplicationRunListener,迴圈呼叫他們的starting方法
封裝命令列引數
接下來就是準備環境,通過debug進入其中
發現,首先建立環境,在回撥SpringApplicationRunListener的environmentPrepared()方法,表示環境準備完成
之後就建立ApplicationContext,進入其中
發現,通過判斷建立不同容器,最後通過反射建立,因為我們這裡是web環境,就會得到AnnotationConfigServletWebServerApplicationContext
接下來,準備上下文
進入其中
發現將之前建立的容器新增到其中,主要呼叫了applyInitializers(context);方法,這個方法時幹啥的呢?進入其中
發現在迴圈所有的ApplicationContextInitializer,回撥他們的initialize()方法,而這些ApplicationContextInitializer就是在SpringApplication建立時,在spring.factories檔案中載入的ApplicationContextInitializer。所有的ApplicationContextInitializer的initialize()方法回撥完畢,有回撥SpringApplicationRunListeners的contextPrepared()方法
接下來
回撥SpringApplicationRunListeners的contextLoaded()方法,至此prepareContext()方法就呼叫完畢,之後來到refreshContext(context);方法,重新整理容器,就是IOC容器初始化的過程
refreshContext(context);執行完畢,IOC容器就建立完畢了,所有的bean就建立完畢,如果是web應用Tomcat或其他Servlet容器也建立完畢,之後就呼叫所有SpringApplicationRunListeners的started()方法
最後呼叫callRunners(context, applicationArguments);方法,進入其中
發現從容器中出的ApplicationRunner及CommandLineRunner,並先呼叫ApplicationRunner在呼叫CommandLineRunner,說明他們之間存在優先順序,之後再呼叫所有SpringApplicationRunListeners的running()方法
最後SpringBoot啟動完成,返回IOC容器
3.核心回撥機制
1.配置在META-INF/spring.factories的ApplicationContextInitializer,SpringApplicationRunListener
2.通過容器獲得的ApplicationRunner,CommandLineRunner,下面我們就看看這幾個類
4.建立各個介面的實現,並配置
1.建立ApplicationContextInitializer實現
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
//需要配置在spring.factories檔案中
public class HelloApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {//監聽ConfigurableApplicationContext
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("HelloApplicationContextInitializer.initialize()方法執行啦!!!!!!!!!!!!!!!!!!!!");
}
}
2.建立SpringApplicationRunListener的實現類
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
//需要配置在spring.factories檔案中
public class HelloSpringApplicationRunListener implements SpringApplicationRunListener {
//必須要有這個構造器
public HelloSpringApplicationRunListener(SpringApplication application, String[] args) {}
//這邊在spring剛拿到所有的SpringApplicationRunListener實現類後就直接呼叫了starting 通知各個SpringApplicationRunListener的實現類
@Override
public void starting() {
System.out.println("HelloSpringApplicationRunListener.starting()呼叫啦!!!!!!!!!!!!");
}
//在準備好了ConfigurableEnvironment環境的時候通知各個實現類
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
Object osName = environment.getSystemProperties().get("os.name");//獲得作業系統名稱
System.out.println("HelloSpringApplicationRunListener.environmentPrepared()呼叫啦!!!!!!!!!!!!"+osName);
}
//在spring 結束applyInitializers後進行通知
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("HelloSpringApplicationRunListener.contextPrepared()呼叫啦!!!!!!!!!!!!");
}
//在載入完資源類(啟動類)後觸發
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("HelloSpringApplicationRunListener.contextLoaded()呼叫啦!!!!!!!!!!!!");
}
//在所有的bean 都初始化後 進行觸發
@Override
public void started(ConfigurableApplicationContext context) {
System.out.println("HelloSpringApplicationRunListener.started()呼叫啦!!!!!!!!!!!!");
}
//在呼叫完所有的ApplicationRunner和CommandLineRunner實現類後呼叫
@Override
public void running(ConfigurableApplicationContext context) {
System.out.println("HelloSpringApplicationRunListener.running()呼叫啦!!!!!!!!!!!!");
}
//應用程式發生故障時呼叫
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("HelloSpringApplicationRunListener.failed()呼叫啦!!!!!!!!!!!!");
}
}
3.建立ApplicationRunner的實現類
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Component//加入到容器中
public class HelloApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("HelloApplicationRunner.run()方法呼叫啦!!!!!!!!!!!!!!");
}
}
4.建立CommandLineRunner的實現類
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component//加入到容器中
public class HelloCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("HelloCommandLineRunner.run()方法呼叫啦!!!!!!!!!!!!!!!");
}
}
5.配置ApplicationContextInitializer及SpringApplicationRunListener,在類路徑下建立spring.factories檔案,編輯為
org.springframework.context.ApplicationContextInitializer=\
com.peng.demo.listener.HelloApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=\
com.peng.demo.listener.HelloSpringApplicationRunListener
6.執行發現,在應用啟動過程中回調了不同的方法,至於在啥時候回撥的,前面流程分析中已有介紹
5.總結
查看了SpringBoot啟動流程,最主要就是ApplicationContextInitializer,SpringApplicationRunListener,ApplicationRunner,CommandLineRunner四個介面實現類方法的回撥,這四個介面的主要作用就是在SpringBoot 啟動初始化的過程中可以通過四個介面實現類方法回撥來讓使用者在啟動的各個流程中可以加入自己的邏輯