首先上一張圖,圖片來自 SpringBoot啟動流程解析
本文基於spring-boot-2.0.4.RELEASE.jar包分析。
程序啟動入口
public static void main(String[] args) {
SpringApplication.run(Springboot2Application.class, args);
}
run
是一個靜態方法,最后會調用創建SpringApplication實例並run
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
我們先看new SpringApplication(xx)構建的實例。
public SpringApplication(Class... primarySources) {
this((ResourceLoader)null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//配置source
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
//判斷是否web應用
this.webApplicationType = this.deduceWebApplicationType();
//創建初始化構造器
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
//創建應用監聽器
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
//推斷出main方法類
this.mainApplicationClass = this.deduceMainApplicationClass();
}
SpringApplication的構造函數主要設置了一些基本參數並配置source、判斷了是否web應用、創建初始化構造器、創建應用監聽器、找出main方法所在的類。
getSpringFactoriesInstances為獲取spring工廠中的實例,具體代碼塊為
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return this.getSpringFactoriesInstances(type, new Class[0]);
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
//獲取類加載器
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
//通過類加載器、獲取指定的spring.factories文件,並獲取文件中工廠類的全路徑名
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//通過類路徑反射得到工廠class對象、構造方法
List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
new SpringApplication(xx)構建完實例后,會進行run方法。
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
//應用啟動計時器開始計時
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
//Headless模式配置
configureHeadlessProperty();
//獲取啟動監聽器
SpringApplicationRunListeners listeners = getRunListeners(args);
//應用啟動監聽器開始計時
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//配置環境模塊(祥見下面prepareEnvironment方法)
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//配置需要忽略的bean
configureIgnoreBeanInfo(environment);
//Banner配置
Banner printedBanner = printBanner(environment);
//創建應用上下文對象
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//上下文基本屬性配置(祥見下面prepareContext方法)
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//更新應用上下文(祥見下面refresh方法)
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 創建配置環境
ConfigurableEnvironment environment = getOrCreateEnvironment();
//加載屬性文件
configureEnvironment(environment, applicationArguments.getSourceArgs());
//監聽器監聽配置
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (this.webApplicationType == WebApplicationType.NONE) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
ConfigurationPropertySources.attach(environment);
return environment;
}
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//加載配置環境
context.setEnvironment(environment);
//ResourceLoader資源加載器
postProcessApplicationContext(context);
//初始化環境
applyInitializers(context);
//配置監聽
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//加載啟動參數
load(context, sources.toArray(new Object[0]));
//監聽加載應用上下文
listeners.contextLoaded(context);
}
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
//准備更新上下文時的預備工作:1.初始化PropertySource; 2.驗證Enrivonment中必要的屬性
this.prepareRefresh();
//獲取上下文中的BeanFactory
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//對BeanFactory做些預備工作
this.prepareBeanFactory(beanFactory);
try {
//對BeanFactory進行預處理
this.postProcessBeanFactory(beanFactory);
//執行容器中的BeanFactoryPostProcessor
this.invokeBeanFactoryPostProcessors(beanFactory);
//注冊BeanPostProcessor
this.registerBeanPostProcessors(beanFactory);
//初始化MessageSource(國際化相關)
this.initMessageSource();
//初始化容器事件廣播器(用來發布事件)
this.initApplicationEventMulticaster();
//初始化一些特殊的Bean,主要做了: 1.初始化ThemeSource(跟國際化相關的接口) 2.創建WebServer
this.onRefresh();
//將所有監聽器注冊到前兩步創建的事件廣播器中
this.registerListeners();
//結束BeanFactory的初始化工作(這一步主要用來將所有的單例BeanDefinition實例化)
this.finishBeanFactoryInitialization(beanFactory);
//上下文刷新完畢
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}