启动流程图(个人理解)
我们都是知道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)
下面我们看他们的具体源码,进行分析
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都有哪些类型
NONE, SERVLET, 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值
privateCollection getSpringFactoriesInstances(Class type) { return getSpringFactoriesInstances(type, new Class>[] {}); }
private监听器集合赋值Collection getSpringFactoriesInstances(Class 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 names = new linkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); //实例化获取的对象集合 List 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();执行run(args)方法
详见另外另一篇博客,地址如下
https://editor.csdn.net/md?not_checkout=1&articleId=123689089



