SpringApplication的创建过程
运行main方法
new SpringApplication(primarySources).run(args)
new SpringApplication(primarySources)
primarySources就是自己的启动类调用如下构造方法
/**
* resourceLoader,此时传的是null
* primarySources 一般的是我们的启动类
*/
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//1.resourceLoader资源加载的,这里为空,按照spring的尿性一般的是**Context,当然这里暂时还没有context
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//启动类不能为空,不然报错
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//2.决定容器的类型,NONE、servlet、REACTIVE①
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//3.初始化器的装载②
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//4.容器监听器的加载③
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//5.返回启动类的class对象④
this.mainApplicationClass = deduceMainApplicationClass();
}
注释:
①容器类型的决定
//存在org.springframework.web.reactive.DispatcherHandler,并且不存在org.springframework.web.servlet.DispatcherServlet并且不存在org.glassfish.jersey.servlet.ServletContainer就是REACTIVE
//javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext都没有就是NONO
//默认就是SERVLET
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;
}
/**
* 判断哪些类在不在,上面classLoader传过来就是null
*
*/
public static Class<?> forName(String name, @Nullable ClassLoader classLoader)
throws ClassNotFoundException, LinkageError {
Assert.notNull(name, "Name must not be null");
//方法1.1,首先判断名字不为空,并且名字长度小于8
Class<?> clazz = resolvePrimitiveClassName(name);
if (clazz == null) {
//1.2commonClassCache主要是java.lang包里面的
clazz = commonClassCache.get(name);
}
if (clazz != null) {
return clazz;
}
//对一些特殊格式的名字支持,递归调用自己
// "java.lang.String[]" style arrays
if (name.endsWith(ARRAY_SUFFIX)) {
String elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length());
Class<?> elementClass = forName(elementClassName, classLoader);
return Array.newInstance(elementClass, 0).getClass();
}
// "[Ljava.lang.String;" style arrays
if (name.startsWith(NON_PRIMITIVE_ARRAY_PREFIX) && name.endsWith(";")) {
String elementName = name.substring(NON_PRIMITIVE_ARRAY_PREFIX.length(), name.length() - 1);
Class<?> elementClass = forName(elementName, classLoader);
return Array.newInstance(elementClass, 0).getClass();
}
// "[[I" or "[[Ljava.lang.String;" style arrays
if (name.startsWith(INTERNAL_ARRAY_PREFIX)) {
String elementName = name.substring(INTERNAL_ARRAY_PREFIX.length());
Class<?> elementClass = forName(elementName, classLoader);
return Array.newInstance(elementClass, 0).getClass();
}
ClassLoader clToUse = classLoader;
if (clToUse == null) {
//默认当前线程的classLoader
//Thread.currentThread().getContextClassLoader()
clToUse = getDefaultClassLoader();
}
try {
//直接调用Class.forName
return Class.forName(name, false, clToUse);
}
catch (ClassNotFoundException ex) {
int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR);
if (lastDotIndex != -1) {
String innerClassName =
name.substring(0, lastDotIndex) + INNER_CLASS_SEPARATOR + name.substring(lastDotIndex + 1);
try {
//上面获取不到判断是不是一个内部类的名字继续Class.forName
return Class.forName(innerClassName, false, clToUse);
}
catch (ClassNotFoundException ex2) {
// Swallow - let original exception get through
}
}
throw ex;
}
}
上面一整套下来解决了一个问题,在这个环境里面有没有某一个类
1.1 primitiveTypeNameMap的数据,resolvePrimitiveClassName方法里面的(m代码未贴出来)
1.2commonClassCache,commonClassCache.get(name);方法的数据,都是java.lang包下面的,这里就直接debug打印
{java.lang.Throwable=class java.lang.Throwable, java.lang.Float=class java.lang.Float, [Ljava.lang.Integer;=class [Ljava.lang.Integer;, [Ljava.lang.Boolean;=class [Ljava.lang.Boolean;, java.lang.Double=class java.lang.Double, java.util.Enumeration=interface java.util.Enumeration, java.lang.Error=class java.lang.Error, [Ljava.lang.Character;=class [Ljava.lang.Character;, [Ljava.lang.Double;=class [Ljava.lang.Double;, java.lang.Integer=class java.lang.Integer, java.lang.AutoCloseable=interface java.lang.AutoCloseable, java.lang.Iterable=interface java.lang.Iterable, java.lang.Character=class java.lang.Character, java.lang.Enum=class java.lang.Enum, java.lang.Long=class java.lang.Long, java.lang.Short=class java.lang.Short, java.util.Map=interface java.util.Map, java.lang.Boolean=class java.lang.Boolean, [Ljava.lang.Number;=class [Ljava.lang.Number;, java.lang.StackTraceElement=class java.lang.StackTraceElement, java.lang.String=class java.lang.String, java.lang.Byte=class java.lang.Byte, java.lang.Number=class java.lang.Number, [Ljava.lang.Float;=class [Ljava.lang.Float;, java.util.Map$Entry=interface java.util.Map$Entry, java.lang.Cloneable=interface java.lang.Cloneable, [Ljava.lang.StackTraceElement;=class [Ljava.lang.StackTraceElement;, java.util.Iterator=interface java.util.Iterator, java.io.Externalizable=interface java.io.Externalizable, java.util.Collection=interface java.util.Collection, [Ljava.lang.Byte;=class [Ljava.lang.Byte;, [Ljava.lang.Class;=class [Ljava.lang.Class;, java.util.Set=interface java.util.Set, java.lang.RuntimeException=class java.lang.RuntimeException, [Ljava.lang.String;=class [Ljava.lang.String;, java.lang.Exception=class java.lang.Exception, java.io.Serializable=interface java.io.Serializable, [Ljava.lang.Object;=class [Ljava.lang.Object;, java.util.List=interface java.util.List, [Ljava.lang.Long;=class [Ljava.lang.Long;, java.io.Closeable=interface java.io.Closeable, [Ljava.lang.Short;=class [Ljava.lang.Short;, java.util.Optional=class java.util.Optional, java.lang.Class=class java.lang.Class, java.lang.Object=class java.lang.Object, java.lang.Comparable=interface java.lang.Comparable}
②
③公用一个方法
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
//类加载器,
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
//从META-INF/spring.factories里面读取配置,注意这一步,这一步很重要2.1
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//实例化,常规反射
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
//排序,怎么排序这次没看,按照以往经验,一般都是实现Order或者PriorityOrdered接口的,或者有@Order的在前面,具体细节本次没看(好吧,其实是看不懂)
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
2.1步骤详解
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
//这一步返回的是一个map
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
//核心步骤,classLoader.getResources,ClassLoader.getSystemResources
//这俩方法是java基础里面的获取资源的方法,最后进行遍历封装到map里面
try {
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryClassName = ((String) entry.getKey()).trim();
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
loadSpringFactories里面的内容
上面这些功能都不大相同,我说一下本人用过的,
1.org.springframework.boot.autoconfigure.EnableAutoConfiguration,这个很简单,你把你的配置类放在META-INF/spring.factories里面,就相当于自己加了@Component注解(意义:别人写的jar包你总不能去里面加注解吧,这个就是实现springboot自动化配置的一个重要步骤)
2.其他的讲道理都没有直接用过,暂时不去了解各个类是干什么的
④
//StackTraceElement在平常debug的时候挺有用的
private Class<?> deduceMainApplicationClass() {
try {
//返回方法的调用栈
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
//找到main方法的类
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
总结
1.SpringApplication的创建到此结束,其中一些loadSpringFactories(META-INF/spring.factories里面加载的还未弄清楚)
2.spring上下文的创建过程参考
3.spring容器的refresh()方法,springbbot里面的refresh还是这个方法执行原理一样