·康忙,先跟着下图走一遍静静心...
-
创建SpringBoot项目 -> main 启动
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
-
-> SpringApplication.run(DemoApplication.class, args)
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);
}
-
-> new SpringApplication,这里只分析初始化,run启动后面分析
public SpringApplication(Class<?>... primarySources) {
this((ResourceLoader)null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
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.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// Set<Class<?>> primarySources:意义在于存放 Java Config 类,这里就是 DemoApplication
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
// 1.通过 classpath ,判断 Web 应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 2.设置 List<ApplicationContextInitializer<?>> initializers
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 3.设置 List<ApplicationListener<?>> listeners
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
// 4.获取调用 main 方法的启动类:Class<?> mainApplicationClass
this.mainApplicationClass = this.deduceMainApplicationClass();
}
目录. 第1. --> WebApplicationType.deduceFromClasspath()
第2与3. --> 都调用 SpringApplication.getSpringFactoriesInstances(),这里拿 type=ApplicationContextInitializer.class 做分析
第4. --> SpringApplication.deduceMainApplicationClass()
第1. --> WebApplicationType.deduceFromClasspath()
static WebApplicationType deduceFromClasspath() {
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;
for(int var2 = 0; var2 < var1; ++var2) {
String className = var0[var2];
if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
return NONE;
}
}
//private static final String[] SERVLET_INDICATOR_CLASSES = new String[]
//{"javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext"}
// 判断classpath下是否存在该数组里面的class,存在则返回 SERVLET
return SERVLET;
}
}
第2与3. --> 都调用 SpringApplication.getSpringFactoriesInstances(),这里拿 type=ApplicationContextInitializer.class 做分析
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) {
ClassLoader classLoader = this.getClassLoader();
// 1. 加载配置文件 'META-INF/spring.factories',并且从中获取指定类型的类名的数组,放入set去重
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 2. 创建对象实例
List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
// 3. 排序对象集合
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
·这里只分析介绍 --> SpringFactoriesLoader.loadFactoryNames()
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
// 获得factoryClassName,我们在这里的 factoryClassName =org.springframework.context.ApplicationContextInitializer.
String factoryClassName = factoryClass.getName();
// 获取 factoryClassName 为key下的 className 集合
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
// 加载 META-INF/spring.factories 文件,信息以 key-value 形式存入 map
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
// 首先从缓存 Map<ClassLoader, MultiValueMap<String, String>> cache 中获取
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;// 缓存中存在,返回
} else {
try {
// 加载 META-INF/spring.factories 文件
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);
// 把resource 转为 properties
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
String factoryClassName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryName = var9[var11];
// 把 factoryClassName 下的所有 className 存入 result中
result.add(factoryClassName, factoryName.trim());
}
}
}
// 放入缓存
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
断点调试查看 result
·以 org.springframework.context.ApplicationContextInitializer 为key的集合中共有6个元素
因为 /Users/~/.m2/repository/org/springframework/boot/spring-boot/2.1.6.RELEASE/spring-boot-2.1.6.RELEASE.jar!/META-INF/spring.factories 中有4个,/Users/~/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.1.6.RELEASE/spring-boot-autoconfigure-2.1.6.RELEASE.jar!/META-INF/spring.factories有2个
# 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
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
·以 org.springframework.context.ApplicationListener 为key的集合中共有10个元素
因为 /Users/~/.m2/repository/org/springframework/boot/spring-boot/2.1.6.RELEASE/spring-boot-2.1.6.RELEASE.jar!/META-INF/spring.factories 中有9个,/Users/~/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.1.6.RELEASE/spring-boot-autoconfigure-2.1.6.RELEASE.jar!/META-INF/spring.factories有1个
# 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
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
· 然后拿着当前class类型下的 names集合,进行实例化(利用反射,就不详细介绍),最后进行排序。
--> classType=ApplicationContextInitializer.class 时获取到的实例如下
--> classType=ApplicationListener.class 时获取到的实例如下
stop......... 从第2、3步中的思绪中跳出来,分析初始化 SpringApplication 的最后一步
第4. --> SpringApplication.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];
// 找到 main 函数的类
if ("main".equals(stackTraceElement.getMethodName())) {
// 获取获取启动类
return Class.forName(stackTraceElement.getClassName());
}
}
} catch (ClassNotFoundException var6) {
}
return null;
}
debug --> 通过寻找 main 方法找到启动类 DemoApplication
赋与私有属性 private Class<?> mainApplicationClass ;主要用于日志的打印
至此,SpringApplication 的初始化就完成啦!