#SpringBoot-V2.1.0.RELEASE源码分析
基于2.1.0.RELEASE做的源码解析
##1. 环境搭建
- 下载
登录github下载当前版本的源码,clone或打包都行
- 解压
解压下载的spring-boot-2.1.0.RELEASE.zip到D盘根目录,路径深度问题,放其他子文件夹报错;
- 编译
进入D:\spring-boot-2.1.0.RELEASE打开命令行窗口,执行maven编译命令,等待…
mvn clean install -DskipTests
- IDEA导入
菜单 File > Open 打开D:\spring-boot-2.1.0.RELEASE\,MavenProject导入D:\spring-boot-2.1.0.RELEASE\spring-boot-project与D:\spring-boot-2.1.0.RELEASE\spring-boot-samples
需要等待较长时间 - 运行
执行D:\spring-boot-2.1.0.RELEASE\spring-boot-samples\spring-boot-sample-simple\src\main\java\sample\simple\SampleSimpleApplication.java类打印正确日志
2. 启动流程
###1. 自身启动代码
@SpringBootApplication
public class SampleSimpleApplication {
public static void main(String[] args) {
SpringApplication.run(SampleSimpleApplication.class, args);
}
}
###2. 静态run方法-参数转换
将可变参数args转成普通字符串数组,将对象参数primarySource转成对象数组,代码如下:
public static ConfigurableApplicationContext run(Class<?> primarySource,
String... args) {
return run(new Class<?>[] { primarySource }, args);
}
###3. 静态run方法-实例创建与run方法调用
- 根据primarySources对象数组创建实例化对象SpringApplication;
- 调用run方法完成应用启动操作;
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) {
return new SpringApplication(primarySources).run(args);
//这种方式调用可以关闭Banner或者spring.main.banner-mode=off
//SpringApplication app = new SpringApplication(SampleSimpleApplication.class);
//app.setBannerMode(Banner.Mode.OFF);/
}
###4. SpringApplication构造实例-添加参数
添加null的ResourceLoader对象用于资源文件处理
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
###5. SpringApplication构造实例-实例化
构造SpringApplication实例,
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//resourceLoader赋值给this.resourceLoader
this.resourceLoader = resourceLoader;
//断言,判断primarySources不是空
Assert.notNull(primarySources, "PrimarySources must not be null");
//将primarySources存入LinkedHashSet对象并赋值给this.primarySources
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//推断当前应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//初始化应用程序上下文
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//初始化监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//推断主类
this.mainApplicationClass = deduceMainApplicationClass();
}
####5.1. 应用类型推断
this.webApplicationType = WebApplicationType.deduceFromClasspath();
- 应用类型枚举
public enum WebApplicationType {
//应用程序不应作为Web应用程序运行,也不应启动嵌入式Web服务器。
NONE,
//应用程序应作为基于servlet的Web应用程序运行,并应启动嵌入式servlet Web服务器。
SERVLET,
//应用程序应作为响应式Web应用程序运行,并应启动嵌入式响应式Web服务器。
REACTIVE
}
- 应用类型推断-通过类路径Classpath
static WebApplicationType deduceFromClasspath() {
//REACTIVE_WEB_ENVIRONMENT_CLASS可加载,并且MVC_WEB_ENVIRONMENT_CLASS和JERSEY_WEB_ENVIRONMENT_CLASS不能加载,则为响应式web应用
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
//javax.servlet.Servlet与org.springframework.web.context.ConfigurableWebApplicationContext不能加载则为非web应用
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
//否则为servlet应用
return WebApplicationType.SERVLET;
}
- 相关静态变量
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";
- ClassUtils
由spring-core-5.1.2.RELEASE.jar包提供,用于完成类的加载注册销毁等
- isPresent() 判断
判断className类是否存在且可以被输入的类加载器classLoader加载
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; } }
- forName() 加载
用于替换JDK中的Class.forName(),它也会返回基元的类实例(例如“int”)和数组类名(例如“String []”)。
此外,它还能够以Java源代码样式解析内部类名(例如“java.lang.Thread.State”而不是“java.lang.Thread $ State”)。
如果找不到或者无法加载类则抛出异常/** Suffix for array class names: {@code "[]"}. */ public static final String ARRAY_SUFFIX = "[]"; /** Prefix for internal array class names: {@code "["}. */ private static final String INTERNAL_ARRAY_PREFIX = "["; /** Prefix for internal non-primitive array class names: {@code "[L"}. */ private static final String NON_PRIMITIVE_ARRAY_PREFIX = "[L"; /** The package separator character: {@code '.'}. */ private static final char PACKAGE_SEPARATOR = '.'; /** The path separator character: {@code '/'}. */ private static final char PATH_SEPARATOR = '/'; /** The inner class separator character: {@code '$'}. */ private static final char INNER_CLASS_SEPARATOR = '$'; public static Class<?> forName(String name, @Nullable ClassLoader classLoader) throws ClassNotFoundException, LinkageError { Assert.notNull(name, "Name must not be null"); //根据JVM的基本类命名规则,将给定的类名解析为基本类(如果适用)。 Class<?> clazz = resolvePrimitiveClassName(name); // if (clazz == null) { 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) { clToUse = getDefaultClassLoader(); } //调用JDK的加载器进行类加载,并将类加载器当作参数传入 try { 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.forName(innerClassName, false, clToUse); } catch (ClassNotFoundException ex2) { // Swallow - let original exception get through } } throw ex; } }
- resolvePrimitiveClassName() 解析原始类型
根据primitiveTypeNameMap获取类型原始映射,如int对应int.class
/** * Map with primitive type name as key and corresponding primitive * type as value, for example: "int" -> "int.class". */ private static final Map<String, Class<?>> primitiveTypeNameMap = new HashMap<>(32); @Nullable public static Class<?> resolvePrimitiveClassName(@Nullable String name) { Class<?> result = null; // Most class names will be quite long, considering that they // SHOULD sit in a package, so a length check is worthwhile. if (name != null && name.length() <= 8) { // Could be a primitive - likely. result = primitiveTypeNameMap.get(name); } return result; }
- getDefaultClassLoader()
获取默认的类加载器
@Nullable public static ClassLoader getDefaultClassLoader() { ClassLoader cl = null; //获取当前线程的类加载器 try { cl = Thread.currentThread().getContextClassLoader(); } catch (Throwable ex) { // Cannot access thread context ClassLoader - falling back... } if (cl == null) { // 获取当前类的类加载器 cl = ClassUtils.class.getClassLoader(); if (cl == null) { // 获取系统类加载器bootstrapClassLoader try { cl = ClassLoader.getSystemClassLoader(); } catch (Throwable ex) { // Cannot access system ClassLoader - oh well, maybe the caller can live with null... } } } return cl; }
- isPresent() 判断
####5.2. 初始化
使用getSpringFactoriesInstances()分别初始化ApplicationContextInitializer与ApplicationListener,并放入initializers与listeners变量
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
- getSpringFactoriesInstances(Class type)
通过Spring工厂实例化type对象
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 duplicate