Spring Boot 啟動過程分析(三)
阿新 • • 發佈:2019-01-31
private void refreshContext(ConfigurableApplicationContext context) {
// 由於這裡需要呼叫父類一系列的refresh操作,涉及到了很多核心操作,因此耗時會比較長,本文不做具體展開
refresh(context);
// 註冊一個關閉容器時的鉤子函式
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
// 呼叫父類的refresh方法完成容器重新整理的基礎操作
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext)applicationContext).refresh();
}
註冊關閉容器時的鉤子函式的預設實現是在 AbstractApplicationContext 類中:
public void registerShutdownHook() {
if(this.shutdownHook == null) {
this.shutdownHook = new Thread() {
public void run() {
synchronized(AbstractApplicationContext.this.startupShutdownMonitor) {
AbstractApplicationContext.this.doClose();
}
}
};
Runtime.getRuntime().addShutdownHook(this .shutdownHook);
}
}
如果沒有提供自定義的shutdownHook,那麼會生成一個預設的,並新增到Runtime中。預設行為就是呼叫它的doClose方法,完成一些容器銷燬時的清理工作。
3.2.6 Spring Context後置處理
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
callRunners(context, args);
}
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<Object>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<Object>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
try {
(runner).run(args);
}
catch (Exception ex) {
throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
}
}
private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
try {
(runner).run(args.getSourceArgs());
}
catch (Exception ex) {
throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
}
}
所謂的後置操作,就是在容器完成重新整理後,依次呼叫註冊的Runners。Runners可以是兩個介面的實現類:
- org.springframework.boot.ApplicationRunner
- org.springframework.boot.CommandLineRunner
CommandLineRunner、ApplicationRunner 介面是在容器啟動成功後的最後一步回撥(類似開機自啟動)
這兩個介面有什麼區別呢:
public interface ApplicationRunner {
void run(ApplicationArguments args) throws Exception;
}
public interface CommandLineRunner {
void run(String... args) throws Exception;
}
其實沒有什麼不同之處,除了介面中的run方法接受的引數型別是不一樣的以外。一個是封裝好的 ApplicationArguments 型別,另一個是直接的String不定長陣列型別。因此根據需要選擇相應的介面實現即可。