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
private Collection 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
Set names = 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<>();
读取地址信息
Enumeration urls = 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
/**
* Original URI, if available; used for URI and File access.
*/
@Nullable
private final URI uri;
/**
* Original URL, used for actual access.
*/
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";
/**
* Boolean flag controlled by a {@code spring.xml.ignore} system property that instructs Spring to
* ignore XML, i.e. to not initialize the XML-related infrastructure.
* The default is "false".
*/
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
java.util.ArrayList
)替换为不可变更集合
// 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
将获取的类实例化List instances = 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
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)