SpringBoot 源码分析 —- SpringApplication

一、启动类

@SpringBootApplication // 标明是Springboot应用,是启动类,可以开启自动配置功能
public class SpringBootStart {
   public static void main(String[] args) {
       // 写本类的字节码【为的就是找到启动类上的注解】启动springboot应用
       // run方法里面做的事情是初始化Spring框架
       SpringApplication.run(SpringBootStart.class, args);
   }
}

二、SpringApplication

org.springframework.boot.SpringApplication ,Spring 应用启动器。就像代码上所添加的注释,它来提供启动 Spring 应用的功能。

Class that can be used to bootstrap and launch a Spring application from a Java main method.

大多数情况下,我们都是使用它提供的静态方法:

// SpringApplication.java

public static void main(String[] args) throws Exception {
SpringApplication.run(new Class<?>[0], args);
}

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
// 创建 SpringApplication 对象,并执行运行。
return new SpringApplication(primarySources).run(args);
}

最终调用的是第 3 个静态方法。而第 3 个静态方法,实现的逻辑就是:

首先,创建一个 SpringApplication 对象。

源码:

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  //  resourceLoader 资源加载器
  this.resourceLoader = resourceLoader;
  Assert.notNull(primarySources, "PrimarySources must not be null");
 // primarySources 主要的 Java Config 类的数组
  this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
 // webApplicationType 调用 WebApplicationType#deduceFromClasspath() 方法,通过 classpath ,判断 Web 应用类型。
  this.webApplicationType = deduceWebApplicationType();
 // Initializers属性 ApplicationContextInitializer 数组。
 // 通过 getSpringFactoriesInstances(Class<T> type) 方法,进行获得 ApplicationContextInitializer 类型的对象数组,
  setInitializers((Collection) getSpringFactoriesInstances(
        ApplicationContextInitializer.class));
  setListeners((Collection)

// listeners 属性,ApplicationListener 数组。
// 也是通过 getSpringFactoriesInstances(Class<T> type) 方法,进行获得 ApplicationListener 类型的对象数组。
                   getSpringFactoriesInstances(ApplicationListener.class));
 // mainApplicationClass 属性,调用 #deduceMainApplicationClass() 方法,获得是调用了哪个 #main(String[] args) 方法,没有什么逻辑上的用途,主要就是用来打印下日志,说明是通过这个类启动 Spring 应用的。
 this.mainApplicationClass = deduceMainApplicationClass();
}
getSpringFactoriesInstances

#getSpringFactoriesInstances(Class<T> type) 方法,获得指定类类对应的对象们。代码如下:

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
     Class<?>[] parameterTypes, Object... args) {
  ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  // Use names and ensure unique to protect against duplicates
 // <1> 加载指定类型对应的,在 `META-INF/spring.factories` 里的类名的数组
  Set<String> names = new LinkedHashSet<>(
        SpringFactoriesLoader.loadFactoryNames(type, classLoader));
 // <2> 创建对象们
  List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
        classLoader, args, names);
 // <3> 排序对象们
  AnnotationAwareOrderComparator.sort(instances);
  return instances;
}
然后,调用 SpringApplication run(Class<?> primarySource, String... args) 方法,运行 Spring 应用。
public ConfigurableApplicationContext run(String... args) {
   // <1> 创建 StopWatch 对象,并启动。StopWatch 主要用于简单统计 run 启动过程的时长。
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
   //
   ConfigurableApplicationContext context = null;
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
   // <2> 配置 headless 属性
   configureHeadlessProperty();
   // 获得 SpringApplicationRunListener 的数组,并启动监听
   SpringApplicationRunListeners listeners = getRunListeners(args);
   listeners.starting();
   try {
       // <3> 创建  ApplicationArguments 对象
       ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
       // <4> 加载属性配置。执行完成后,所有的 environment 的属性都会加载进来,包括 application.properties 和外部的属性配置。
       ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
       configureIgnoreBeanInfo(environment);
       // <5> 打印 Spring Banner
       Banner printedBanner = printBanner(environment);
       // <6> 创建 Spring 容器。
       context = createApplicationContext();
       // <7> 异常报告器
       exceptionReporters = getSpringFactoriesInstances(
               SpringBootExceptionReporter.class,
               new Class[] { ConfigurableApplicationContext.class }, context);
       // <8> 主要是调用所有初始化类的 initialize 方法
       prepareContext(context, environment, listeners, applicationArguments,
               printedBanner);
       // <9> 初始化 Spring 容器。
       refreshContext(context);
       // <10> 执行 Spring 容器的初始化的后置逻辑。默认实现为空。
       afterRefresh(context, applicationArguments);
       // <11> 停止 StopWatch 统计时长
       stopWatch.stop();
       // <12> 打印 Spring Boot 启动的时长日志。
       if (this.logStartupInfo) {
           new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
       }
       // <13> 通知 SpringApplicationRunListener 的数组,Spring 容器启动完成。
       listeners.started(context);
       // <14> 调用 ApplicationRunner 或者 CommandLineRunner 的运行方法。
       callRunners(context, applicationArguments);
   } catch (Throwable ex) {
       // <14.1> 如果发生异常,则进行处理,并抛出 IllegalStateException 异常
       handleRunFailure(context, ex, exceptionReporters, listeners);
       throw new IllegalStateException(ex);
   }

   // <15> 通知 SpringApplicationRunListener 的数组,Spring 容器运行中。
   try {
       listeners.running(context);
   } catch (Throwable ex) {
       // <15.1> 如果发生异常,则进行处理,并抛出 IllegalStateException 异常
       handleRunFailure(context, ex, exceptionReporters, null);
       throw new IllegalStateException(ex);
   }
   return context;
}

发表评论