32 SpringBoot啟動原理與流程
阿新 • • 發佈:2018-12-29
1 啟動原理
1.1 入口(Springboot27Application.java)
@SpringBootApplication
public class Springboot27Application {
public static void main(String[] args) {
SpringApplication.run(Springboot27Application.class, args);
}
}
1.2 開始啟動(SpringBootApplication.java)
public static ConfigurableApplicationContext run (Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
/*
專案啟動分為2步
1: new SpringApplication(primarySources)
建立SpringApplication物件
2: .run(args)
執行run方法
*/
return (new SpringApplication(primarySources)).run(args);
}
1.2.1 建立SpringApplication物件
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.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.isCustomEnvironment = false;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
// 1 獲取應用型別
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 從類路徑下找到META-INF/spring.factories配置的所有ApplicationContextInitializer,然後儲存起來
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 3 從類路徑下找到META-INF/spring.factories配置的所有ApplicationListener
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
// 4 從多個配置類中找到有main方法的主配置類
this.mainApplicationClass = this.deduceMainApplicationClass();
}
1.2.1.1 獲取應用型別
static WebApplicationType deduceFromClasspath() {
// 根據容器中指定的類是否存在來判斷應用型別
if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
return REACTIVE;
} else {
String[] var0 = SERVLET_INDICATOR_CLASSES;
int var1 = var0.length;
for(int var2 = 0; var2 < var1; ++var2) {
String className = var0[var2];
if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
return NONE;
}
}
return SERVLET;
}
}
1.2.1.2 配置的所有ApplicationContextInitializer
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = this.getClassLoader();
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
......
return instances;
}
- SpringFactoriesLoader.loadFactoryNames
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
// 從類路徑下找到META-INF/spring.factories配置的所有ApplicationContextInitializer
// eg: org/springframework/boot/spring-boot-autoconfigure/2.1.0.RELEASE/spring-boot-autoconfigure-2.1.0.RELEASE.jar!/META-INF/spring.factories
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
/*
從類路徑下找到META-INF/spring.factories配置的所有ApplicationContextInitializer
eg: org/springframework/boot/spring-boot-autoconfigure/2.1.0.RELEASE/spring-boot-autoconfigure-2.1.0.RELEASE.jar!/META-INF/spring.factories
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
*/
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
......
// 儲存起來
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
1.2.1.3 配置的所有ApplicationListener
原理與 1.2.1.2 中一致
1.2.1.4 配置的所有ApplicationListener
1.2.2 執行run方法
public ConfigurableApplicationContext run(String... args) {
// 1 監聽
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 2 宣告一個空的IOC容器
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
// 3 獲取SpringApplicationRunListeners: 底層使用getSpringFactoriesInstances()方法獲取,原理與1.2.1.2中一致(從類路徑下META-INF/spring.factories)
SpringApplicationRunListeners listeners = this.getRunListeners(args);
// 4 回撥所有的獲取SpringApplicationRunListener.starting()方法
listeners.starting();
Collection exceptionReporters;
try {
// 5 封裝命令列引數(專案啟動時,可以在命令列中指定引數)
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//6 準備環境,建立環境完成後回撥SpringApplicationRunListener.environmentPrepared();表示環境準備完成
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
// 7 列印banner圖示
Banner printedBanner = this.printBanner(environment);
// 8 建立ApplicationContext : 建立IOC容器
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
/*
9 準備上下文環境
將配置好的環境放入IOC容器
applyInitializers():回撥之前儲存的所有的ApplicationContextInitializer的initialize方法(1.2.1.2)
回撥所有的SpringApplicationRunListener的contextPrepared();
prepareContext執行完成以後回撥所有的SpringApplicationRunListener的contextLoaded()
*/
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 10 重新整理容器 : ioc容器初始化(如果是web應用還會建立嵌入式的Tomcat)
// 掃描,建立,載入所有元件的地方;(配置類,元件,自動配置)
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
/*
11 從ioc容器中獲取所有的ApplicationRunner和CommandLineRunner進行回撥
ApplicationRunner先回調,CommandLineRunner再回調
*/
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
//整個SpringBoot應用啟動完成以後返回啟動的ioc容器;
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
1.2.2.1 獲取SpringApplicationRunListeners
1.2.2.2 準備環境
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
// 判斷環境是否存在,存在及獲取,不存在及建立
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
// 配置環境
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
// 建立環境完成後回撥SpringApplicationRunListener.environmentPrepared();表示環境準備完成
listeners.environmentPrepared((ConfigurableEnvironment)environment);
this.bindToSpringApplication((ConfigurableEnvironment)environment);
if (!this.isCustomEnvironment) {
environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
1.2.2.3 準備上下文環境
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
// 將配置好的環境放入IOC容器
context.setEnvironment(environment);
// 後置處理
this.postProcessApplicationContext(context);
// 回撥之前儲存的所有的ApplicationContextInitializer的initialize方法
this.applyInitializers(context);
// 回撥所有的SpringApplicationRunListener的contextPrepared(1.2.1.3)
listeners.contextPrepared(context);
// 日誌記錄
if (this.logStartupInfo) {
this.logStartupInfo(context.getParent() == null);
this.logStartupProfileInfo(context);
}
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 將命令列引數註冊進來
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
// 將banner註冊
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
Set<Object> sources = this.getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
this.load(context, sources.toArray(new Object[0]));
// 回撥所有的SpringApplicationRunListener的contextLoaded()
listeners.contextLoaded(context);
}