public SpringApplication(ResourceLoader resourceLoader, Class>... primarySources) {
// 传入的资源加载器为null,在执行run方法中对其赋值默认值
// org.springframework.boot.SpringApplication#run(java.lang.String...)
// Banner printedBanner = printBanner(environment);
// ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader : new DefaultResourceLoader(getClassLoader());
// org.springframework.util.ClassUtils#getDefaultClassLoader
// Thread.currentThread().getContextClassLoader()
this.resourceLoader = resourceLoader;
// 主类不能为空(传入空数组new Class>[0]可以跳过此验证)
Assert.notNull(primarySources, "PrimarySources must not be null");
// 可以有多个主类进入,但是只有当前启动的main方法的类是后面的mainApplication,其他的做为资源类加入BeanFactory中管理
// private Set> primarySources;
// 关联参考:org.springframework.boot.SpringApplication#getAllSources
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 通过反射加载相关应用类,来推断web应用的类型
// WebApplicationType.REACTIVE
// WebApplicationType.NONE
// WebApplicationType.SERVLET 当前项目默认启动就是servlet
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 自动装配:加载配置于/META-INF/spring.factories中key为org.springframework.context.ApplicationContextInitializer的所有初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 同上操作,加载监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 通过栈推断main方法所在的启动类,在spring cloud 中的bootstrap启动中会利用此主类
// 参考org.springframework.cloud.bootstrap.BootstrapApplicationListener#bootstrapServiceContext
// StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
this.mainApplicationClass = deduceMainApplicationClass();
}
1.自动装配 setInitializers
// orgspringframeworkbootspring-boot2.2.4.RELEASEspring-boot-2.2.4.RELEASE.jar!META-INFspring.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.rsocket.context.RSocketPortInfoApplicationContextInitializer, org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer // orgspringframeworkbootspring-boot-autoconfigure2.2.4.RELEASEspring-boot-autoconfigure-2.2.4.RELEASE.jar!META-INFspring.factories # Initializers org.springframework.context.ApplicationContextInitializer= org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer, org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
源码分析setInitializers:
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
a.获取所有的初始化器实例对象:
// org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class, java.lang.Class>[], java.lang.Object...) private Collection getSpringFactoriesInstances(Class type, Class>[] parameterTypes, Object... args) { // parameterTypes = new Class>[] {} 为空 // args 为空 // 获取classLoader ClassLoader classLoader = getClassLoader(); // Use names and ensure unique to protect against duplicates // 根据传入的类和classLoader加载META-INF/spring.factories中的配置 Set names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // 创建配置实例对象 List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); // 排序 AnnotationAwareOrderComparator.sort(instances); return instances; }
b.获取META-INF/spring.factories文件指定key的配置:
// org.springframework.core.io.support.SpringFactoriesLoader#loadFactoryNames public static ListloadFactoryNames(Class> factoryType, @Nullable ClassLoader classLoader) { String factoryTypeName = factoryType.getName(); // 从所有配置中获取指定的配置 return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); }
c.加载META-INF/spring.factories文件的所有配置:
private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) { // 先看看缓存中有没有,有就返回,springboot第一次肯定没有,但是spring cloud当使用bootstrap启动时,bootstrap会创建SpringApplication子容器,加缓存可以提高效率 MultiValueMap result = cache.get(classLoader); if (result != null) { return result; } try { // classLoader != null // FACTORIES_RESOURCE_LOCATION = META-INF/spring.factories Enumeration urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry, ?> entry : properties.entrySet()) { String factoryTypeName = ((String) entry.getKey()).trim(); for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) { result.add(factoryTypeName, factoryImplementationName.trim()); } } } // 以类加载器为key,将加载的自动装配的配置文件放入map缓存中 // private static final Map > cache = new ConcurrentReferenceHashMap<>(); cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }
d.反射加载实例对象:
// org.springframework.boot.SpringApplication#createSpringFactoriesInstances private2.自动装配 setListenersList createSpringFactoriesInstances(Class type, Class>[] parameterTypes, ClassLoader classLoader, Object[] args, Set names) { // parameterTypes = new Class>[] {} // args 为空 List instances = new ArrayList<>(names.size()); for (String name : names) { try { // 反射加载初始化器的类信息 Class> instanceClass = ClassUtils.forName(name, classLoader); // 验证父类的实例是否可以从子类得到分配 // superType.isAssignableFrom(subType) Assert.isAssignable(type, instanceClass); // 反射获取构造器 Constructor> constructor = instanceClass.getDeclaredConstructor(parameterTypes); // 反射创建实例java.lang.reflect.Constructor#newInstance T instance = (T) BeanUtils.instantiateClass(constructor, args); instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex); } } return instances; }
// orgspringframeworkbootspring-boot2.2.4.RELEASEspring-boot-2.2.4.RELEASE.jar!META-INFspring.factories # Application Listeners org.springframework.context.ApplicationListener= org.springframework.boot.ClearCachesApplicationListener, org.springframework.boot.builder.ParentContextCloserApplicationListener, org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor, 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 // orgspringframeworkbootspring-boot-autoconfigure2.2.4.RELEASEspring-boot-autoconfigure-2.2.4.RELEASE.jar!META-INFspring.factories # Application Listeners org.springframework.context.ApplicationListener= org.springframework.boot.autoconfigure.BackgroundPreinitializer
源码和初始化器一致
3.deduceMainApplicationClass()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;
}
SpringApplication的构造方法总结
- 赋值加载器,加载器为null,后续使用默认加载器
- 验证主配置类不能为空
- 推断当前项目的web类型
- 自动装配初始化器
- 自动装配监听器
- 通过栈推断main方法所在的启动类



