SpringBoot-V2.1.0.RELEASE源码分析

#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方法调用

  1. 根据primarySources对象数组创建实例化对象SpringApplication;
  2. 调用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;
      }
      

####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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值