框架:SpringBoot 之 SpringApplication源码深度解析(上)
总算是怀着热切的心情打开了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的相应事件。