org.springframework.boot.StringApplication
public SpringApplication(Class>... primarySources) {
this(null, primarySources);
}
org.springframework.boot.StringApplication
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 = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
设置资源加载器
this.resourceLoader = resourceLoader; // null判断基础源非空
Assert.notNull(primarySources, "PrimarySources must not be null");设置基础源
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));设置web应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath(); // WebApplicationType.NONE
— deduceFromClasspath start
org.springframework.util.ClassUtils.WebApplicationType
private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
通过判断org.springframework.web.servlet.DispatcherServlet、org.springframework.web.reactive.DispatcherHandler等类是否存在返回相应类型
WebApplicationType.REACTIVE 响应式
WebApplicationType.SERVLET 服务式
WebApplicationType.NONE 非web应用
— deduceFromClasspath end
this.bootstrapRegistryInitializers = new ArrayList<>( getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); // []
读取配置文件中org.springframework.boot.BootstrapRegistryInitializer接口的实现类名并实例化
org.springframework.boot.StringApplication privateCollection getSpringFactoriesInstances(Class type) { return getSpringFactoriesInstances(type, new Class>[] {}); }
— getSpringFactoriesInstances start
org.springframework.boot.StringApplication private获取类加载器Collection getSpringFactoriesInstances(Class type, Class>[] parameterTypes, Object... args) { ClassLoader classLoader = getClassLoader(); // Use names and ensure unique to protect against duplicates Set names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }
ClassLoader classLoader = getClassLoader(); // Launcher$AppClassLoader
—— getClassLoader start
org.springframework.boot.StringApplication
public ClassLoader getClassLoader() {
if (this.resourceLoader != null) {
return this.resourceLoader.getClassLoader();
}
return ClassUtils.getDefaultClassLoader();
}
此时资源加载器为null,执行getDefaultClassLoader方法。
——— getDefaultClassLoader start
org.springframework.boot.StringApplication
public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
}
catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back...
}
if (cl == null) {
// No thread context class loader -> use class loader of this class.
cl = ClassUtils.class.getClassLoader();
if (cl == null) {
// getClassLoader() returning null indicates the bootstrap ClassLoader
try {
cl = ClassLoader.getSystemClassLoader();
}
catch (Throwable ex) {
// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
}
}
}
return cl;
}
——— getDefaultClassLoader end
—— getClassLoader end
此时获取到当前线程的上下文类加载器Launcher$AppClassLoader
Setnames = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // []
—— loadFactoryNames start
org.springframework.core.io.support.SpringFactoriesLoader public static List获取工厂类型loadFactoryNames(Class> factoryType, @Nullable ClassLoader classLoader) { ClassLoader classLoaderToUse = classLoader; if (classLoaderToUse == null) { classLoaderToUse = SpringFactoriesLoader.class.getClassLoader(); } String factoryTypeName = factoryType.getName(); return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList()); }
String factoryTypeName = factoryType.getName();读取名称集合并返回
return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());先读取全部集合
loadSpringFactories(classLoaderToUse)
——— loadSpringFactories start
org.springframework.core.io.support.SpringFactoriesLoader private static Map先从缓存获取> loadSpringFactories(ClassLoader classLoader) { Map > result = cache.get(classLoader); if (result != null) { return result; } result = new HashMap<>(); try { Enumeration urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION); 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(); String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String) entry.getValue()); for (String factoryImplementationName : factoryImplementationNames) { result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>()) .add(factoryImplementationName.trim()); } } } // Replace all lists with unmodifiable lists containing unique elements result.replaceAll((factoryType, implementations) -> implementations.stream().distinct() .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList))); cache.put(classLoader, result); } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } return result; }
Map> result = cache.get(classLoader); // null if (result != null) { return result; }
org.springframework.core.io.support.SpringFactoriesLoader static final Map>> cache = new ConcurrentReferenceHashMap<>();
org.springframework.util.ConcurrentReferenceHashMap默认为软连接集合,适用于缓存
当内存不足时,只有软连接的实例可被gc清除
此时缓存为null
result = new HashMap<>();读取地址信息
Enumerationurls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
org.springframework.core.io.support.SpringFactoriesLoader public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
———— getResources start
java.lang.ClassLoader public Enumeration查看复合枚举类的构造方法getResources(String var1) throws IOException { Enumeration[] var2 = (Enumeration[])(new Enumeration[2]); if (this.parent != null) { var2[0] = this.parent.getResources(var1); } else { var2[0] = getBootstrapResources(var1); } var2[1] = this.findResources(var1); return new CompoundEnumeration(var2); }
————— CompoundEnumeration start
sun.misc.CompoundEnumeration private Enumeration[] enums; public CompoundEnumeration(Enumeration [] var1) { this.enums = var1; }
即sun.misc.CompoundEnumeration是包含java.util.Enumeration数组的实例
————— CompoundEnumeration end
方法返回包含两个element的sun.misc.CompoundEnumeration枚举实例,第一个为递归调用父级加载器获取的地址信息枚举(sun.misc.CompoundEnumeration),第二个为自身获取的地址信息(匿名java.util.Enumeration
———— getResources end
默认共存在三处配置文件
spring-boot-2.6.5.jar、spring-beans-5.3.17.jar、spring-boot-autoconfigure-2.6.5.jar
while (urls.hasMoreElements())
———— while start
获取当前地址实例URL url = urls.nextElement();转换为org.springframework.core.io.UrlResource实例
UrlResource resource = new UrlResource(url);
————— UrlResource start
org.springframework.core.io.UrlResource
@Nullable
private final URI uri;
private final URL url;
public UrlResource(URL url) {
Assert.notNull(url, "URL must not be null");
this.uri = null;
this.url = url;
}
————— UrlResource end
读取文件Properties properties = PropertiesLoaderUtils.loadProperties(resource);
————— loadProperties start
org.springframework.core.io.support.PropertiesLoaderUtils
public static Properties loadProperties(Resource resource) throws IOException {
Properties props = new Properties();
fillProperties(props, resource);
return props;
}
创建属性集合实例
Properties props = new Properties();
java.util.Properties继承java.util.Hashtable,可看作java.util.Map实例
填充实例fillProperties(props, resource);
org.springframework.core.io.support.PropertiesLoaderUtils
private static final String XML_FILE_EXTENSION = ".xml";
private static final boolean shouldIgnoreXml = SpringProperties.getFlag("spring.xml.ignore");
public static void fillProperties(Properties props, Resource resource) throws IOException {
try (InputStream is = resource.getInputStream()) {
String filename = resource.getFilename();
if (filename != null && filename.endsWith(XML_FILE_EXTENSION)) {
if (shouldIgnoreXml) {
throw new UnsupportedOperationException("XML support disabled");
}
props.loadFromXML(is);
}
else {
props.load(is);
}
}
}
返回实例
return props;
————— loadProperties end
遍历配置项for (Map.Entry, ?> entry : properties.entrySet())
————— for start
获取工厂类名称String factoryTypeName = ((String) entry.getKey()).trim();获取实现类名称数组
String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
—————— commaDelimitedListToStringArray start
org.springframework.util.StringUtils
public static String[] commaDelimitedListToStringArray(@Nullable String str) {
return delimitedListToStringArray(str, ",");
}
public static String[] delimitedListToStringArray(@Nullable String str, @Nullable String delimiter) {
return delimitedListToStringArray(str, delimiter, null);
}
public static String[] delimitedListToStringArray(
@Nullable String str, @Nullable String delimiter, @Nullable String charsToDelete) {
if (str == null) {
return EMPTY_STRING_ARRAY;
}
if (delimiter == null) {
return new String[] {str};
}
List result = new ArrayList<>();
if (delimiter.isEmpty()) {
for (int i = 0; i < str.length(); i++) {
result.add(deleteAny(str.substring(i, i + 1), charsToDelete));
}
}
else {
int pos = 0;
int delPos;
while ((delPos = str.indexOf(delimiter, pos)) != -1) {
result.add(deleteAny(str.substring(pos, delPos), charsToDelete));
pos = delPos + delimiter.length();
}
if (str.length() > 0 && pos <= str.length()) {
// Add rest of String, but not in case of empty input.
result.add(deleteAny(str.substring(pos), charsToDelete));
}
}
return toStringArray(result);
}
以为逗号分隔符得到名称数组
—————— commaDelimitedListToStringArray end
for (String factoryImplementationName : factoryImplementationNames) {
result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
.add(factoryImplementationName.trim());
}
————— for end
———— while end
// Replace all lists with unmodifiable lists containing unique elements result.replaceAll((factoryType, implementations) -> implementations.stream().distinct() .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));将结果集放入缓存
cache.put(classLoader, result);返回结果集
return result;
——— loadSpringFactories end
根据类型名称获取名称集合getOrDefault(factoryTypeName, Collections.emptyList())
—— loadFactoryNames end
将获取的类实例化Listinstances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
—— createSpringFactoriesInstances start
org.springframework.boot.StringApplication private创建与类名称集合大小相同的实例集合List createSpringFactoriesInstances(Class type, Class>[] parameterTypes, ClassLoader classLoader, Object[] args, Set names) { List 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; }
List遍历类名称instances = new ArrayList<>(names.size());
for (String name : names)
——— for start
根据类名获取类实例Class> instanceClass = ClassUtils.forName(name, classLoader);判断当前类是否为指定接口的实现类
Assert.isAssignable(type, instanceClass);根据参数类型获取当前类的构造器
Constructor> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
此时parameterTypes为空数组,即获取无参构造器
根据构造器将当前类实例化T instance = (T) BeanUtils.instantiateClass(constructor, args);将实例加入集合
instances.add(instance);
——— for end
返回实例集合return instances;
—— createSpringFactoriesInstances end
将实例集合进行排序AnnotationAwareOrderComparator.sort(instances);
即根据org.springframework.core.annotation.Order指定的值排序
返回实例集合return instances;
— getSpringFactoriesInstances end
此时共创建0个引导注册器初始器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
getSpringFactoriesInstances方法上文已分析,后面不再赘述
此时共创建7个初始器
org.springframework.boot.context.config.DelegatingApplicationContextInitializer
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer
org.springframework.boot.context.ContextIdApplicationContextInitializer
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
— setInitializers start
org.springframework.boot.StringApplication
private List> initializers;
public void setInitializers(Collection extends ApplicationContextInitializer>> initializers) {
this.initializers = new ArrayList<>(initializers);
}
— setInitializers end
设置监听器setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
此时共创建8个监听器
org.springframework.boot.env.EnvironmentPostProcessorApplicationListener
org.springframework.boot.context.config.AnsiOutputApplicationListener
org.springframework.boot.context.logging.LoggingApplicationListener
org.springframework.boot.autoconfigure.BackgroundPreinitializer
org.springframework.boot.context.config.DelegatingApplicationListener
org.springframework.boot.builder.ParentContextCloserApplicationListener
org.springframework.boot.ClearCachesApplicationListener
org.springframework.boot.context.FileEncodingApplicationListener
— setListeners start
org.springframework.boot.StringApplication
private List> listeners;
public void setListeners(Collection extends ApplicationListener>> listeners) {
this.listeners = new ArrayList<>(listeners);
}
— setListeners end
推断main函数所在类this.mainApplicationClass = deduceMainApplicationClass(); // StudyApplication.class
— deduceMainApplicationClass start
org.springframework.boot.StringApplication
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函数所在类
— deduceMainApplicationClass end
通常情况下将应用的入口main函数直接定义在应用入口类中,即primarySource==mainApplicationClass



