启动流程图(个人理解)
我们都是知道SpringBoot启动其实了类似下面的代码
自动定义启动类代码
@Configuration
@Component
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class StudySpringApplication {
public static void main(String[] args) {
SpringApplication.run(StudySpringApplication.class, args);
}
}
其实里面较为核心代码是
SpringApplication.run(StudySpringApplication.class, args);
启动类源码
下面我们就开始对这个代码的源码进行分析
首先进到对应的方法里面
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
首先我们来解读下改方法上的注释
原文
Static helper that can be used to run a SpringApplication from the specified sources using default settings and user supplied arguments.
Params:
primarySources – the primary sources to load
args – the application arguments (usually passed from a Java main method)
Returns:
the running ApplicationContext
翻译后的(加上个人理解)
该静态方法主要根据用户提供主启动类和其他参数,实例化一个SpringApplication,并返回一个ApplicationContext
参数:
primarySources–要加载的主要源
args–应用程序参数(通常从Java主方法传递)
返回:
运行中的应用上下文(ApplicationContext)
上面的源码我们拆分成两部分来分析,
一、new SpringApplication(primarySources)实例化对象,
二、执行run(args)
下面我们看他们的具体源码,进行分析
实例化对象new SpringApplication(primarySources)
核心源码
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//赋值操作
//要使用的资源加载器赋值
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//核心启动类不能为空
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//对应用类型赋值
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//初始化集合赋值
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//监听器集合赋值
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//获取主启动类集合
this.mainApplicationClass = deduceMainApplicationClass();
}
注释分析
注释原文
Create a new SpringApplication instance. The application context will load beans from the specified primary sources (see class-level documentation for details. The instance can be customized before calling run(String...).
Params:
resourceLoader – the resource loader to use
primarySources – the primary bean sources
See Also:
run(Class, String[]), setSources(Set)
翻译原文
创建一个新的SpringApplication实例。应用程序上下文将从指定的主源加载bean。可以在调用run(String…)之前自定义实例。
参数:
resourceLoader–要使用的资源加载器
primarySources–主要的bean源
该实例主要方法:
run(Class, String[]), setSources(Set)
源码拆解分析
对于资源加载器和主启动类属性赋值,较为简单没有分析必要
对应用类型赋值
SpringBoot启动时,在创建SpringApplication的构造方法内会调用枚举WebApplicationType的deduceFromClasspath方法获得应用类型并设置当前应用是普通web应用、响应式web应用还是非web应用。
this.webApplicationType = WebApplicationType.deduceFromClasspath();
我们先看下webApplicationType都有哪些类型
/**
* The application should not run as a web application and should not start an
* embedded web server.
*/
NONE,
/**
* The application should run as a servlet-based web application and should start an
* embedded servlet web server.
*/
SERVLET,
/**
* The application should run as a reactive web application and should start an
* embedded reactive web server.
*/
REACTIVE;
NONE:应用程序不作为web应用启动,不启动内嵌的服务。
SERVLET:应用程序以基于servlet的web应用启动,需启动内嵌servlet web服务。
REACTIVE:应用程序以响应式web应用启动,需启动内嵌的响应式web服务。
源码:
private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";
private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";
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;
}
我们通过对上面的源码分析,发现它的核心方法是ClassUtils.isPresent()方法,该方法源码是
public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {
try {
forName(className, classLoader);
return true;
} catch (IllegalAccessError var3) {
throw new IllegalStateException("Readability mismatch in inheritance hierarchy of class [" + className + "]: " + var3.getMessage(), var3);
} catch (Throwable var4) {
return false;
}
}
isPresent()方法调用了forName()方法,如果在调用forName()方法的过程中出现异常则返回false,也就是目标类不存在。否则,返回true。
public static Class<?> forName(String name, @Nullable ClassLoader classLoader) throws ClassNotFoundException, LinkageError {
Assert.notNull(name, "Name must not be null");
Class<?> clazz = resolvePrimitiveClassName(name);
if (clazz == null) {
clazz = (Class)commonClassCache.get(name);
}
if (clazz != null) {
return clazz;
} else {
Class elementClass;
String elementName;
if (name.endsWith("[]")) {
elementName = name.substring(0, name.length() - "[]".length());
elementClass = forName(elementName, classLoader);
return Array.newInstance(elementClass, 0).getClass();
} else if (name.startsWith("[L") && name.endsWith(";")) {
elementName = name.substring("[L".length(), name.length() - 1);
elementClass = forName(elementName, classLoader);
return Array.newInstance(elementClass, 0).getClass();
} else if (name.startsWith("[")) {
elementName = name.substring("[".length());
elementClass = forName(elementName, classLoader);
return Array.newInstance(elementClass, 0).getClass();
} else {
ClassLoader clToUse = classLoader;
if (classLoader == null) {
clToUse = getDefaultClassLoader();
}
try {
return Class.forName(name, false, clToUse);
} catch (ClassNotFoundException var9) {
int lastDotIndex = name.lastIndexOf(46);
if (lastDotIndex != -1) {
String innerClassName = name.substring(0, lastDotIndex) + '$' + name.substring(lastDotIndex + 1);
try {
return Class.forName(innerClassName, false, clToUse);
} catch (ClassNotFoundException var8) {
}
}
throw var9;
}
}
}
}
初始化集合赋值
//初始化集合赋值
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
根据当前类名,去找到所有包含META-INF/spring.factories的jar包,获取文件中该类名(ApplicationContextInitializer)为key值的value值
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的jar包,获取该类名为key值的value值
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//实例化获取的对象集合
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
//根据@Order注解进行排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
监听器集合赋值
//监听器集合赋值
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
集合获取方法同上,根据当前类名,去找到所有META-INF/spring.factories的jar包,获取该类名为key值的value值,然后返回根据@order注解排序后的实例化集合。
获取主启动类集合
this.mainApplicationClass = deduceMainApplicationClass();