来看下SpringApplication.java的构造函数大体流程图
来看下具体的函数截图
1.resourceLoader成员变量的赋值,由于我们通过通过run(xx.class)方式来运行的.所以这种方式resourceLoader=null,
2.primarySources这个成员变量就是我们传来的class了.
3.webApplicationType这个按照我的理解,应该是WebApplicationType.SERVLET.
4.setInitializers.这个是获取需要初始化的对象,这个具体实现有点复杂,先来看截图
这里是通过SpringFactoriesLoader类的loadFactoryNames函数来得到所有的需要初始化的类名.其实现方式在这里大体说一下.
1).通过传进来的classloader对象的getResources接口,获取URL
2).通过URL获取inputstream
3).Properties.load(inputstream)的方式读取文件中所有数据.其文件名为
public static final String FACTORIES_RESOURCE_LOCATION = “META-INF/spring.factories”;
4).对每一个property的value值,进行解析.因为其中可能包括多个类名.
5).通过反射的方式,获取传递进来Class的类名.然后将这个类名与所有的属性key进行比对,通过就返回value的list列表.大体是这样
这里传进来的是ApplicationContextInitializer.class.那么看我运行的程序打印
看到没,第一行是key . factoryName.从第二行开始就是其需要获取的东西了.这里有四个需要初始化的类名.
获取了所有需要的类名后,还剩最后一步.就是实例化.看其实现
这里首先是通过类名获取Class.
其实通过传递进来的paramerType参数,来得到其Constructor
再次就是使用反射的方式得到具体的实例了,这里需要注意的是args其实是个{},里面没数据.所以生成的对象构造函数里面应该都是赋的null值.
setInitializers最后一步是将所有的对象添加到list中去.
5.setListeners
这个具体实现与上面一模一样,只不过传的参数不一样,它传递的是ApplicationListener.class这个.来看下具体的获取的是什么,程序打印如下:
6.构造函数最后一步mainApplicationClass成员变量的赋值.根据其执行的函数分析,其就是获取我们当前程序最初运行的类名.就是那个有main开始执行的类
最后贴下测试代码吧,有兴趣的可以自己试.
spring.factories //这个数据来源于spring.boot包下来的那个WEB_INFO
# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\r
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
# Error Reporters
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers
# 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
# 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
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor
# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer
# FailureAnalysisReporters
org.springframework.boot.diagnostics.FailureAnalysisReporter=\
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter
TestFactXml.java读取测试这个配置文件
package com.bruk;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
public class TestFactXml {
final static String FACTORIES_RESOURCE_LOCATION="spring.factories";
public static void main(String[] args){
ClassLoader load = Thread.currentThread().getContextClassLoader();
HashMap<String,List<String>> map = new LinkedHashMap<>();
System.out.println("args="+args);
try {
Enumeration<URL> urls = load.getResources(FACTORIES_RESOURCE_LOCATION);
//result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
System.out.println(url.getFile());
// UrlResource resource = new UrlResource(url);
// Properties properties = PropertiesLoaderUtils.loadProperties(resource);
InputStream inputStream = getInputStream(url);
Properties props = new Properties();
props.load(inputStream);
for (Map.Entry<?, ?> entry : props.entrySet()) {
String factoryClassName = ((String) entry.getKey()).trim();
System.out.println("factoryClassName "+factoryClassName);
for (String factoryName : delimitedListToStringArray((String) entry.getValue() , "," , null)) {
//result.add(factoryClassName, factoryName.trim());
System.out.println(factoryName.trim());
List<String> values = map.computeIfAbsent(factoryClassName, k -> new LinkedList<>());
values.add( factoryName);
}
// Set<String> names = new LinkedHashSet<>(map);
System.out.println("===========================================================");
}
}
List<String> list= map.getOrDefault("org.springframework.context.ApplicationContextInitializer",Collections.emptyList());
for (String name : list) {
System.out.println("find name is "+name.trim());
}
}catch(Exception E){
System.out.println(E.getMessage());
}
}
public static String[] delimitedListToStringArray(
String str, String delimiter, String charsToDelete) {
if (str == null) {
return new String[0];
}
if (delimiter == null) {
return new String[]{str};
}
List<String> 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), ","));
}
}
Collection<String> collection = result;
return collection.toArray(new String[0]);
}
public static String deleteAny(String inString, String charsToDelete) {
if (!hasLength(inString) || !hasLength(charsToDelete)) {
return inString;
}
StringBuilder sb = new StringBuilder(inString.length());
for (int i = 0; i < inString.length(); i++) {
char c = inString.charAt(i);
if (charsToDelete.indexOf(c) == -1) {
sb.append(c);
}
}
return sb.toString();
}
public static boolean hasLength( CharSequence str) {
return (str != null && str.length() > 0);
}
static public InputStream getInputStream(URL url) {
//ResourceUtils.useCachesIfNecessary(con);
try {
URLConnection con = url.openConnection();
return con.getInputStream();
} catch (Exception ex) {
// Close the HTTP connection (if applicable).
}
return null;
}
}