總算是懷着熱切的心情打開了spring boot的源碼,大四北京實習用過的框架,都是回憶呀。
啓動類,都是調用SpringApplication的run()方法,傳入的是加入@Configuration註解的類,跟參數:
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);
}
先初始化了SpringApplication的實例然後調用run方法。先看其構造吧:
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = deduceWebApplicationType();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
在其雙參構造方法中可以看到,先是保存傳入的resourceLoader,對資源非null斷言,將資源primarySources按照有序LinkedSet形式存儲,調用deduceWebApplication()方法推斷出webApplication的類型,然後設置initializers、listeners、用deduceMainApplicationClass()方法得出並設置mainApplicationClass。
先看deduceWebApplication()方法:
private WebApplicationType deduceWebApplicationType() {
if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_WEB_ENVIRONMENT_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
可以看到這裏通過ClassUtils類的isPresent()方法檢查classpath中是否有相應的類來判斷類型:
private static final String[] WEB_ENVIRONMENT_CLASSES =
{ "javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext" };
public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework."
+ "web.reactive.DispatcherHandler";
private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework."
+ "web.servlet.DispatcherServlet";
private static final String JERSEY_WEB_ENVIRONMENT_CLASS = "org.glassfish.jersey.server.ResourceConfig";
如果有dispatcherHandler,且沒有DispatcherServlet、jersy的就是Reactive類型,如果沒有WEB_ENVIRONMENT_CLASSES
指定的類,那麼則None類型,否則Servlet類型。
在設置Initializers時首先調用getSpringFactoriesInstances()方法加載ApplicationContextInitializer,然後直接賦值給initializers:
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
可以看到這裏通過spring容器來實現IoC。先得到contextClassLoader,然後調用SpringFactoriesLoader的loadFactoryNames傳入factoryClass得到該Class下配置的類名的集合,這裏使用set來存,保證類名不重複。然後調用createSpringFactoriesInstances()方法,得到對應的實例的集合,再排序返回。
我們先來看下loadFactoryNames()方法的邏輯:
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
先得到factoryClass的名字,這裏即org.springframework.context.ApplicationContextInitializer,然後調用loadSpringFactories()傳入ClassLoader,得到map,然後用factoryClass的名字作爲key去get:
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 {
Enumeration<URL> urls = classLoader != null?classLoader.getResources("META-INF/spring.factories")
:ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
List<String> factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray
((String)entry.getValue()));
result.addAll((String)entry.getKey(), factoryClassNames);
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var9) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9);
}
}
}
這兒有個MultiValueMap類型的緩存,如果緩存裏面有classLoader加載過的,那麼直接返回,否則重新加載。先得到ClassLoader加載的urls,如果ClassLoader爲null那麼從ClassLoader默認的系統配置中去取,否則從ClassLoader中去取"META-INF/spring.factories"路徑下的urls。然後遍歷urls,取出每個url對應的properties文件,取出其中的鍵值對加入到LinkedMultiValueMap中,最後以ClassLoader爲key,LinkedMultiValueMap爲value加入到cache中緩存。返回的是LinkedMultiValueMap(該ClassLoader下的所有的urls指向的資源裏的properties中的鍵值對,其中值可能含有多個結果於是用list存儲)。
然後從返回的LinkedMultiValueMap中按照factoryClassName爲key,去取的對應的value集合。其中spring-boot/META-INF/spring.factories中org.springframework.context.ApplicationContextInitializer的值如下:
# 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
再來關注下SpringApplication的createSpringFactoriesInstances()方法:
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
這個邏輯很簡單,先遍歷類名的集合,通過ClassUtils的forName反射出每個類名對應的類,再得到其對應的構造方法,再調用BeanUtils的instantiateClass()反射得到具體實例對象,加入到instances集合中。返回。然後加到initializers中。
設置listener還是一樣的方法,調用getSpringFactoriesInstances加載META-INF/spring.factories中配置的org.springframework.context.ApplicationListener指定的類,然後得到實例加到listeners中:
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
然後調用deduceMainApplicationClass()方法得到mainApplicationClass:
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
通過獲取當前方法調用棧,遍歷找到main函數的類。
下面構造完成了,我們來看看SpringApplication實例的run方法:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
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;
}
先創建StopWatch做爲計時工具,然後調用其start方法,記錄當前時間即開始計時:
public void start() throws IllegalStateException {
this.start("");
}
public void start(String taskName) throws IllegalStateException {
if(this.currentTaskName != null) {
throw new IllegalStateException("Can't start StopWatch: it's already running");
} else {
this.currentTaskName = taskName;
this.startTimeMillis = System.currentTimeMillis();
}
}
我們可以看看StopWatch的stop停止計時:
public void stop() throws IllegalStateException {
if(this.currentTaskName == null) {
throw new IllegalStateException("Can't stop StopWatch: it's not running");
} else {
long lastTime = System.currentTimeMillis() - this.startTimeMillis;
this.totalTimeMillis += lastTime;
this.lastTaskInfo = new StopWatch.TaskInfo(this.currentTaskName, lastTime);
if(this.keepTaskList) {
this.taskList.add(this.lastTaskInfo);
}
++this.taskCount;
this.currentTaskName = null;
}
}
初始化TaskInfo傳入開始時間,結束時間。將Task加入TaskList中,taskCount++,再currentTaskName設爲null,表示現在沒計時任務。
然後調用configureHeadlessProperty設置SYSTEM_PROPERTY_JAVA_AWT_HEADLESS系統屬性,這裏headless默認值爲true,表示是Headless模式,在缺少顯示屏、鍵盤或者鼠標時的系統配置:
private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";
private void configureHeadlessProperty() {
System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(
SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}
然後調用getRunListenners():
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
在這裏可以看到又用了同樣的方法得到getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, arg)得到SpringApplicationRunListener類名爲key,在META-INF/spring.factories裏的值:
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
只加載了EventPublishingRunListener類,我們看其構造方法:
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
這裏構造了一個SimpleApplicationEventMulticaster(Spring默認的事件廣播器)實例,並且把之前在SpringApplication中配置的listeners添加到SimpleApplicationEventMulticaster中。
然後跟log一起封裝成SpringApplicationRunListeners:
SpringApplicationRunListeners(Log log,
Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList<>(listeners);
}
緊接下來就直接調用其starting方法:
public void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
我們知道,這個listeners其實只有一個,EventPublishingRunListener的實例。我們看到EventPublishingRunListener的starting方法中:
@Override
public void starting() {
this.initialMulticaster.multicastEvent(
new ApplicationStartingEvent(this.application, this.args));
}
調用的是內部的SimpleApplicationEventMulticaster的multicastEvent方法,傳入新構造的ApplicationStartingEvent實例:
public void multicastEvent(ApplicationEvent event) {
this.multicastEvent(event, this.resolveDefaultEventType(event));
}
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = eventType != null?eventType:this.resolveDefaultEventType(event);
Iterator var4 = this.getApplicationListeners(event, type).iterator();
while(var4.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var4.next();
Executor executor = this.getTaskExecutor();
if(executor != null) {
executor.execute(() -> {
this.invokeListener(listener, event);
});
} else {
this.invokeListener(listener, event);
}
}
}
先通過getApplicationListenners得到處理該事件的Listenner集合:
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
Object source = event.getSource();
Class<?> sourceType = source != null?source.getClass():null;
AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType);
AbstractApplicationEventMulticaster.ListenerRetriever retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey);
if(retriever != null) {
return retriever.getApplicationListeners();
} else if(this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader))) {
Object var7 = this.retrievalMutex;
synchronized(this.retrievalMutex) {
retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey);
if(retriever != null) {
return retriever.getApplicationListeners();
} else {
retriever = new AbstractApplicationEventMulticaster.ListenerRetriever(true);
Collection<ApplicationListener<?>> listeners = this.retrieveApplicationListeners(eventType, sourceType, retriever);
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
}
} else {
return this.retrieveApplicationListeners(eventType, sourceType, (AbstractApplicationEventMulticaster.ListenerRetriever)null);
}
}
先通過傳入的event構造cacheKey,先去緩存中查找結果,如果結果不爲null,那麼直接返回,否則調用retrieveApplicationListeners,如果需要緩存即滿足以下條件(this.beanClassLoader==null|| ClassUtils.isCacheSafe(event.getClass(),this.beanClassLoader)&&(sourceType==null|| ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)),那麼需要加鎖,且將新生成的retriever以cacheKey爲鍵存入cache中。我們從下面retrieveApplicationListeners的實現中可以看到,遍歷Listenners跟listenerBeans通過supportsEvent判斷Listenner是否支持該事件,支持則加入到處理的集合中:
private Collection<ApplicationListener<?>> retrieveApplicationListeners(ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable AbstractApplicationEventMulticaster.ListenerRetriever retriever) {
LinkedList<ApplicationListener<?>> allListeners = new LinkedList();
Object var7 = this.retrievalMutex;
LinkedHashSet listeners;
LinkedHashSet listenerBeans;
synchronized(this.retrievalMutex) {
listeners = new LinkedHashSet(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet(this.defaultRetriever.applicationListenerBeans);
}
Iterator var14 = listeners.iterator();
while(var14.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var14.next();
if(this.supportsEvent(listener, eventType, sourceType)) {
if(retriever != null) {
retriever.applicationListeners.add(listener);
}
allListeners.add(listener);
}
}
if(!listenerBeans.isEmpty()) {
BeanFactory beanFactory = this.getBeanFactory();
Iterator var16 = listenerBeans.iterator();
while(var16.hasNext()) {
String listenerBeanName = (String)var16.next();
try {
Class<?> listenerType = beanFactory.getType(listenerBeanName);
if(listenerType == null || this.supportsEvent(listenerType, eventType)) {
ApplicationListener<?> listener = (ApplicationListener)beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if(!allListeners.contains(listener) && this.supportsEvent(listener, eventType, sourceType)) {
if(retriever != null) {
retriever.applicationListenerBeans.add(listenerBeanName);
}
allListeners.add(listener);
}
}
} catch (NoSuchBeanDefinitionException var13) {
;
}
}
}
AnnotationAwareOrderComparator.sort(allListeners);
return allListeners;
}
當前listeners中:
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
listenerBeans集合爲空,其中支持ApplicationStartedEvent事件的Listenner剩下:
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
回到SimpleApplicationEventMulticaster的multicastEvent方法,在得到相關事件的listenners集合後,然後遍歷listeners,如果listener有線程池則通過線程池執行invokeListener,沒有的話則直接執行:
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = this.getErrorHandler();
if(errorHandler != null) {
try {
this.doInvokeListener(listener, event);
} catch (Throwable var5) {
errorHandler.handleError(var5);
}
} else {
this.doInvokeListener(listener, event);
}
}
繼續調用doInvokeListener,如果有error的函數句柄,則try-catch,出錯執行:
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
} catch (ClassCastException var6) {
String msg = var6.getMessage();
if(msg != null && !this.matchesClassCastMessage(msg, event.getClass().getName())) {
throw var6;
}
Log logger = LogFactory.getLog(this.getClass());
if(logger.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, var6);
}
}
}
執行listener的相應事件。