创建SpringApplication实例

创建SpringApplication实例,第1张

构造方法
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.DispatcherServletorg.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
方法返回包含两个elementsun.misc.CompoundEnumeration枚举实例,第一个为递归调用父级加载器获取的地址信息枚举(sun.misc.CompoundEnumeration),第二个为自身获取的地址信息(匿名java.util.Enumeration
———— getResources end
默认共存在三处配置文件
spring-boot-2.6.5.jarspring-beans-5.3.17.jarspring-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> 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> 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

至此,SpringApplication实例创建完成

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/874238.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存