springboot啓動分析
一、啓動類
@SpringBootApplication
public class SpringBootStudyApplication {
public static void main(String[] args) {
// spring boot 啓動入口
SpringApplication.run(SpringBootStudyApplication.class, args);
}
}
二、實例化SpringApplication對象
// org.springframework.boot.SpringApplication.SpringApplication
// SpringApplication的靜態run方法,進入重載方法run
public static ConfigurableApplicationContext run(Class<?> primarySource,
String... args) {
return run(new Class<?>[] { primarySource }, args);
}
// 實例化SpringApplication對象,然後調用成員方法run(args)
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) {
return new SpringApplication(primarySources).run(args);
}
// 進入構造器重載方法
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
// 實例化SpringApplication
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 將配置的class保存起來
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 自動推斷出webApplication容器的類型(servlet)
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 從META-INF/spring.factories文件中讀取ApplicationContextInitializer實現類,並且實例化(ApplicationContextInitializer接口在spring-context包下,只有一個抽象方法,可以在spring容器refresh刷新前進行一些其他操作)
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 從META-INF/spring.factories文件中讀取ApplicationListener實現類
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 從參數primarySources數組中推斷出存在main方法的class
this.mainApplicationClass = deduceMainApplicationClass();
}
三、調用SpringApplication的run(args)方法
AbstractApplicationContext.refresh()分析
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
// 開始計時
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 從META-INF/spring.factories文件中獲取SpringApplicationRunListener實現類,並且實例化
//(SpringApplicationRunListener實現類必須要有一個帶參的構造器,參數列表是:SpringApplication application, String[] args),
// listeners保存了SpringApplicationRunListener集合
SpringApplicationRunListeners listeners = getRunListeners(args);
// 該方法其實調用的是遍歷SpringApplicationRunListener的同名方法starting()
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 準備配置環境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
// 忽視一些bean類
configureIgnoreBeanInfo(environment);
// 打印banner圖標
Banner printedBanner = printBanner(environment);
// 根據前面構造器方法中推斷出的容器類型來創建ApplicationContext容器
context = createApplicationContext();
// 從spring.factories文件中獲取異常報告器,根據參數進行實例化
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 準備context容器,會調用ApplicationContextInitializer實現類的initial方法
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
// 會調用AbstractApplicationContext的refresh()方法
refreshContext(context);
// 容器刷新後處理,默認空方法,讓子類進行實現
afterRefresh(context, applicationArguments);
// 統計運行的時間,進行打印日誌
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
// 遍歷調用SpringApplicationRunListener的started(context)方法
listeners.started(context);
// 調用ApplicationRunner和CommandLineRunner的run方法
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// 遍歷調用SpringApplicationRunListener的started(context)方法
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}