@TOC
前言
由于最近個人工作不太繁忙,之前想看SpringBoot 源碼, 今天終于能研究研究了。個人簡單過了一邊SpringApplication.run() 方法的流程 這里記錄一下。
這里將run方法中一些比較復(fù)雜的方法 在代碼中加了注釋
有錯誤希望指正!
SpringApplication.run() 方法 看注釋
public ConfigurableApplicationContext run(String... args) {
//創(chuàng)建時間記錄類&啟動時間記錄
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//變量
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
//設(shè)置系統(tǒng)屬性
configureHeadlessProperty();
//創(chuàng)建所有 Spring 運行監(jiān)聽器并發(fā)布應(yīng)用啟動事件
//遍歷執(zhí)行所有通過SpringFactoriesLoader可以查找到并加載的SpringApplicationRunListener
SpringApplicationRunListeners listeners = getRunListeners(args);
//告訴這些SpringApplicationRunListener SpringBoot開始執(zhí)行了
listeners.starting();
try {
//初始化對象
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//加載服務(wù)&系統(tǒng)資源
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
//打印SpringBoot 啟動日志 就那個圖形化日志
//Banner的日志
Banner printedBanner = printBanner(environment);
//通過SpringBoot 初始化獲得的 容器類型 創(chuàng)建響應(yīng)的ConfigurableApplicationContext
context = createApplicationContext();
//再次借助Spring-FactoriesLoader,查找并加載classpath中所有可用的ApplicationContext-Initializer, 然后遍歷調(diào)用這些ApplicationContextInitializer的initialize(applicationContext)方法來對已經(jīng)創(chuàng)建好的ApplicationContext進(jìn)行進(jìn)一步的處理。
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context);
//獲取 對創(chuàng)建的context 進(jìn)行封裝 將environment 賦值到Context中
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//spring 核心方法 內(nèi)部調(diào)用 ((AbstractApplicationContext) applicationContext).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;
}
configureHeadlessProperty()
//在System系統(tǒng)中設(shè)置 屬性
private void configureHeadlessProperty() {
System.setProperty("java.awt.headless", System.getProperty("java.awt.headless", Boolean.toString(this.headless)));
}
getRunListeners()
//創(chuàng)建所有 Spring 運行監(jiān)聽器并發(fā)布應(yīng)用啟動事件
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
prepareEnvironment() & configureIgnoreBeanInfo()
prepareEnvironment()
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach((Environment)environment);
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;
}
configureIgnoreBeanInfo()
private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
if (System.getProperty("spring.beaninfo.ignore") == null) {
Boolean ignore = (Boolean)environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE);
System.setProperty("spring.beaninfo.ignore", ignore.toString());
}
}

image.png
//加載服務(wù)&系統(tǒng)資源
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
這一步 會獲取到上圖的 environment 對象 會獲取到配置等信息
printBanner()
//打印SpringBoot 啟動日志 就那個圖形化日志
private Banner printBanner(ConfigurableEnvironment environment) {
if (this.bannerMode == Mode.OFF) {
return null;
} else {
ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader : new DefaultResourceLoader(this.getClassLoader());
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter((ResourceLoader)resourceLoader, this.banner);
return this.bannerMode == Mode.LOG ? bannerPrinter.print(environment, this.mainApplicationClass, logger) : bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}
}

image.png
服務(wù)啟動 打印圖形化日志 那個方法
createApplicationContext();
//創(chuàng)建 ConfigurableApplicationContext 對象
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch(this.webApplicationType) {
case SERVLET:
contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
break;
case REACTIVE:
contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
break;
default:
contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
}
} catch (ClassNotFoundException var3) {
throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
}
}
return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
}
getSpringFactoriesInstances()
// springboot 自動裝配 方法 獲取 META-INF/spring.factories 文件下的所有
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = this.getClassLoader();
//loadFactoryNames()這個方法中 調(diào)用 loadSpringFactories(@Nullable ClassLoader classLoader) 方法 這個方法是加載 META-INF/spring.factories 文件中的內(nèi)容
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
prepareContext()
//對進(jìn)行 context 封裝 將BeanFactory 賦值
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
this.postProcessApplicationContext(context);
this.applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
this.logStartupInfo(context.getParent() == null);
this.logStartupProfileInfo(context);
}
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
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]));
listeners.contextLoaded(context);
}
refreshContext()
refreshContext( ) 方法 調(diào)用是 refresh( )方法 Spring 的入口
//spring 核心方法 內(nèi)部調(diào)用 ((AbstractApplicationContext) applicationContext).refresh()
這里就需要對Spring的源碼需要了解了
//Spring 核心方法 內(nèi)部調(diào)用 ((AbstractApplicationContext) applicationContext).refresh()
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext)applicationContext).refresh();
}