第1章 main入口
public static void main(String[] args) {
//代码很简单SpringApplication.run();
SpringApplication.run(ConsumerApp.class, args);
}
public static ConfigurableApplicationContext run(Class<?> primarySource,
String... args) {
//这个里面调用了run() 方法,我们转到定义
return run(new Class<?>[] { primarySource }, args);
}
//这个run方法代码也很简单,就做了两件事情
//1、new了一个SpringApplication() 这么一个对象
//2、执行new出来的SpringApplication()对象的run()方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) {
return new SpringApplication(primarySources).run(args);
}
上面代码主要做了两件事情。
-
第一步new了一个SpringApplication对象
-
第二步调用了run()方法。
1.1 SpringApplication
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//1、先把主类保存起来
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//2、判断运行项目的类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//3、扫描当前路径下META-INF/spring.factories文件的,加载ApplicationContextInitializer接口实例
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//4、扫描当前路径下META-INF/spring.factories文件的,加载ApplicationListener接口实例
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
1.1.1 判断运行环境
构造方法内会调用枚举WebApplicationType的deduceFromClasspath方法获得应用类型并设置当前应用是普通web应用、响应式web应用还是非web应用。
this.webApplicationType = WebApplicationType.deduceFromClasspath();
deduceFromClasspath方法由枚举WebApplicationType提供,具体实现如下:
static WebApplicationType deduceFromClasspath() {
//当classpath下只存在org.springframework.web.reactive.DispatcherHandler,
//且不存在org.springframework.web.servlet.DispatcherServlet,也不存在
//org.glassfish.jersey.servlet.ServletContainer则运行环境为reactive,该模式是非阻塞模式
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;
}
推断的过程中重点调用了ClassUtils.isPresent()方法,用来判断指定类名的类是否存在,是否可以进行加载。ClassUtils.isPresent()方法源代码如下:
public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {
try {
forName(className, classLoader);
return true;
}
catch (IllegalAccessError err) {
throw new IllegalStateException("Readability mismatch in inheritance hierarchy of class [" +
className + "]: " + err.getMessage(), err);
}
catch (Throwable ex) {
// Typically ClassNotFoundException or NoClassDefFoundError...
return false;
}
}
isPresent()方法调用了forName()方法,如果在调用forName()方法的过程中出现异常则返回false,也就是目标类不存在。否则,返回true。
看一下forName()方法的部分代码:
public static Class<?> forName(String name, @Nullable ClassLoader classLoader)
throws ClassNotFoundException, LinkageError {
// 此处省略一些非空和基础类型的判断逻辑代码
ClassLoader clToUse = classLoader;
if (clToUse == null) {
//如果为空则获取默认classLoader
clToUse = getDefaultClassLoader();
}
try {
// 返回加载户的Class。
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 {
return Class