使用了很長時間的springboot了,一直都知道它簡單易用,簡化了框架的搭建過程,但是還是不知道它是如何啟動的,今天就跟着springboot的源碼,去探探這其中的奧妙
以下是spring應用的啟動:
@SpringBootApplication
public class Application extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
//加載配置文件
System.setProperty("spring.config.location","classpath:db_config.properties,classpath:mq.properties");
SpringApplication.run(Application.class, args);
}
}
然后我們跟着Run方法進去
public ConfigurableApplicationContext run(String... args) {
//一開始就是一個StopWatch 類,這個類的主要作用是記錄容器啟動用時
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
this.configureHeadlessProperty();
//加載SPI文件
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
Banner printedBanner = this.printBanner(environment);
context = this.createApplicationContext();
new FailureAnalyzers(context);
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
listeners.finished(context, (Throwable)null);
stopWatch.stop();
if(this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9);
throw new IllegalStateException(var9);
}
}
第一步:可以看到,一開始是一個StopWatch類,該類的作用比較單一,就是記錄springboot的啟動用時,我們啟動springboot完成后會在控制台springboot啟動所花的時間,就是由它來完成的
//然后我們看看this.createApplicationContext()方法:
private void configureHeadlessProperty() {
System.setProperty("java.awt.headless", System.getProperty("java.awt.headless", Boolean.toString(this.headless)));
}
//主要是用來設置系統屬性,具體這個屬性有何作用,有待探究
第二步:創建SpringApplicationRunListeners
//接下來我們看看springboot是如何去初始化監聽器SpringApplicationRunListeners的。this.getRunListeners(args)方法如下:
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, new Object[]{this, args}));
}
//利用傳入的參數args去創建一個SpringApplicationRunListeners實例,此處會去獲取一個SpringFactory的實例,下面我們重點看看是如何來獲取該SpringFactory實例的
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
//首先獲取當前線程的類加載器,然后通過SpringFactoriesLoader去加載SpringApplicationRunListener這個類,接下來看看在加載SpringApplicationRunListener這個spring應用的運行監聽器時做了什么事情
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
Enumeration ex = classLoader != null?classLoader.getResources("META-INF/spring.factories"):ClassLoader.getSystemResources("META-INF/spring.factories");
ArrayList result = new ArrayList();
while(ex.hasMoreElements()) {
URL url = (URL)ex.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
} catch (IOException var8) {
throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
}
}
//首先通過當前線程的類加載器獲取Springboot項目META-INF下面的spring.factories文件,找到該文件,我們可以看到該文件中配置了PropertySource Loaders(屬性來源加載)、運行監聽器EventPublishingRunListener、運用上下文初始化工具、應用監聽器等等一系列的自動化配置,都是從這里加載到應用中來的。加載完成之后,SpringFactory通過反射來獲取這些類的實例,然后放入到SpringApplicationRunListeners中,至此,SpringApplicationRunListeners初始化完成。這里,我們看看SpringApplicationRunListeners中有些什么,源碼如下:
class SpringApplicationRunListeners {
private final Log log;
private final List<SpringApplicationRunListener> listeners;
SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList(listeners);
}
}
//有一個log,用於記錄日志,然后就是一個final的list,里面就是之前初始化時從配置中獲取的各種listener
第三步:啟動SpringApplicationRunListeners中所有的監聽器
第四步:環境准備
第五步:打印Banner
第六步:創建上下文