new SpringApplication实例化过程
SpringBoot启动类
@SpringBootApplication
public class StartApplication {
public static void main(String[] args) {
SpringApplication.run(StartApplication.class, args);
}
}
其中SpringApplication.run()
就是用来启动SpringBoot项目。
看一下这个run()
方法的调用的关系源码:
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
primarySource
:运行的主程序
args
:应用参数
因为主程序可以不止为一个,所以把当前主要资源类放入熟组中。
要完成项目的启动,首先主要资源类要实例化一个SpringApplication
对象,然后调用这个对象的run
方法。因此,分析整个启动过程要分成两部分。这里记录SpringApplication
实例化过程
SpringApplication实例化过程
image.pngpublic SpringApplication(Class... primarySources) {
this((ResourceLoader)null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
//1.给属性附上默认值
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.isCustomEnvironment = false;
this.lazyInitialization = false;
this.resourceLoader = resourceLoader;
//2.断言primarySources即主配置类不能null。若为null,就会报错
Assert.notNull(primarySources, "PrimarySources must not be null");
//3.保存主配置类且去重
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
//4.判断当前是否为WEB应用
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//5.从类路径下的META-INF/spring.factories中查找所有的ApplicationContextInitializer.class初始化器,并且保存起来
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
//6. 从类路径下的META-INF/spring.factories中查找所有的ApplicationListener.class监听器,并且保存起来
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
//7.从多个配置类中找到有main方法的主配置类
this.mainApplicationClass = this.deduceMainApplicationClass();
}
主要分析4-7过程。
1.判断当前是否为WEB应用
this.webApplicationType = WebApplicationType.deduceFromClasspath();
其中deduceFromClasspath
方法如下
public enum WebApplicationType {
//非WEB项目
NONE,
//SERVLET WEB项目
SERVLET,
//响应式WEB项目
REACTIVE;
private static final String[] SERVLET_INDICATOR_CLASSES = new String[]{"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"};
static WebApplicationType deduceFromClasspath() {
//判读是否为响应式WEB项目
if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
return REACTIVE;
} else {
String[] var0 = SERVLET_INDICATOR_CLASSES;
int var1 = var0.length;
//判断是否为非WEB项目
for(int var2 = 0; var2 < var1; ++var2) {
String className = var0[var2];
if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
return NONE;
}
}
return SERVLET;
}
}
其中ClassUtils.isPresent()
判断当前类加载器是否存在对应的类型。
最后可以看出该项目为SERVLET WEB项目。
2.保存所有的初始化器
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
setInitializers()
方法就是将所有的ApplicationContextInitializer
初始化器实例的集合初始化并保存,放在initializers中。
public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList(initializers);
}
getSpringFactoriesInstances
方法如下:
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return this.getSpringFactoriesInstances(type, new Class[0]);
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
//1.获取类加载器
ClassLoader classLoader = this.getClassLoader();
//2.将类路径META-INF/spring.factories中的初始化查找放入集合中并且去重
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//3.根据类名构建类对应的实例了
List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
//4.将实例化列表进行排序
AnnotationAwareOrderComparator.sort(instances);
//5.返回初始化器的实例化列表
return instances;
}
2.1.获取类加载器
ClassLoader classLoader = this.getClassLoader();
其中getClassLoader()
代码如下:
public ClassLoader getClassLoader() {
return this.resourceLoader != null ? this.resourceLoader.getClassLoader() : ClassUtils.getDefaultClassLoader();
}
//查找类加载类
@Nullable
public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
} catch (Throwable var3) {
;
}
if (cl == null) {
cl = ClassUtils.class.getClassLoader();
if (cl == null) {
try {
cl = ClassLoader.getSystemClassLoader();
} catch (Throwable var2) {
;
}
}
}
return cl;
}
2.2查找初始化器放入LinkedHashSet中
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
查看loadFactoryNames
方法:
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
String factoryTypeName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryImplementationName = var9[var11];
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
从类路径下的META-INF/spring.factories中查找所有的ApplicationContextInitializer.class初始化器
其中spring-boot-autoconfigure-2.2.5.RELEASE.jar中的初始化器相关配置:
image.png
获得的 names:
image.png
2.3根据类名构建类对应的实例
List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
createSpringFactoriesInstances
如下:
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {
List<T> instances = new ArrayList(names.size());
Iterator var7 = names.iterator();
while(var7.hasNext()) {
String name = (String)var7.next();
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
T instance = BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
} catch (Throwable var12) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, var12);
}
}
return instances;
}
获得instances如下:
image.png
2.4将实例化列表进行排序
AnnotationAwareOrderComparator.sort(instances);
2.5返回初始化器的实例化列表
return instances;
最终返回的instances:
image.png
3.保存所有的监听器
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
和初始化器获取的方式一致,最终获得的监听器的实例化列表为:
image.png
4.从多个配置类中找到有main方法的主配置类
this.mainApplicationClass = this.deduceMainApplicationClass();
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = (new RuntimeException()).getStackTrace();
StackTraceElement[] var2 = stackTrace;
int var3 = stackTrace.length;
for(int var4 = 0; var4 < var3; ++var4) {
StackTraceElement stackTraceElement = var2[var4];
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
} catch (ClassNotFoundException var6) {
;
}
return null;
}
循环遍历异常栈中的方法名,看那个配置类有main
发放,有的话返回为主配置类。
总结
配合Spring一起看更加美味哦
网友评论