springboot(十四) 源码分析 —— SpringApplication的创建

SpringApplication的创建 

基于 2.2.9.RELEASE的版本,启动项目debug

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

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

run方法最后的走到SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) 来实例化我们的SpringApplication

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  // 1.1 this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 1.2 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 1.3 this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 1.4 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 1.5 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 1.6 this.mainApplicationClass = deduceMainApplicationClass(); }

1.1 resourceLoader 属性,资源加载器

此处debug显示为null;感兴趣的小伙伴可以看一看:Spring 统一资源加载策略(https://blog.csdn.net/cuiwjava/article/details/108940768

springboot(十四) 源码分析 —— SpringApplication的创建 

1.2 primarySources 属性,主要的 Java Config 类的数组

在此处就是对应我们的启动类 DemoApplication 类。

 

1.3 webApplicationType 属性,调用 WebApplicationType#deduceFromClasspath() 方法,通过 classpath ,判断 Web 应用类型

    static WebApplicationType deduceFromClasspath() {
      // WebApplicationType.REACTIVE 类型 if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; }
      // WebApplicationType.NONE 类型 for (String className : SERVLET_INDICATOR_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } }
    // WebApplicationType.SERVLET 类型。可以酱紫的判断的原因是,引入 Spring MVC 时,如果是内嵌的 Web 应用,会引入 Servlet 类。 return WebApplicationType.SERVLET; }

1.4 initializers 属性,ApplicationContextInitializer 数组

通过 #getSpringFactoriesInstances(Class<T> type) 方法,进行获得 ApplicationContextInitializer 类型的对象数组。

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = getClassLoader();
        // 1.4.1 加载指定类型对应的,在 `META-INF/spring.factories` 里的类名的数组
        Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
     // 1.4.2 创建对象们 List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
      // 1.4.3 排序对象们 AnnotationAwareOrderComparator.sort(instances); return instances; }

1.4.1,调用 SpringFactoriesLoader#loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) 方法,加载指定类型对应的,在 META-INF/spring.factories 里的类名的数组。在 META-INF/spring.factories 文件中,会以 KEY-VALUE 的格式,配置每个类对应的实现类们。关于 SpringFactoriesLoader 的该方法,我们就不去细看了。

1.4.2,调用 #createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) 方法,创建对象们。代码如下:

    private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
            ClassLoader classLoader, Object[] args, Set<String> names) {
        List<T> instances = new ArrayList<>(names.size());
        for (String name : names) {
            try {
          // 获得 name 对应的类 Class<?> instanceClass = ClassUtils.forName(name, classLoader);
          // 判断类是否实现自 type 类 Assert.isAssignable(type, instanceClass);
          // 获得构造方法 Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
          // 创建对象 T instance = (T) BeanUtils.instantiateClass(constructor, args); instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex); } } return instances; }

1.4.3,调用 AnnotationAwareOrderComparator#sort(List<?> list) 方法,排序对象们。例如说,类上有 @Order 注解。 

当前Demo是在 Spring MVC 的环境下,initializers 属性的结果如下图:

springboot(十四) 源码分析 —— SpringApplication的创建

 1.5 listeners 属性,ApplicationListener 数组

也是通过 #getSpringFactoriesInstances(Class<T> type) 方法,进行获得 ApplicationListener 类型的对象数组。listeners 属性的结果如下图:

springboot(十四) 源码分析 —— SpringApplication的创建

 1.6 mainApplicationClass 属性

调用 #deduceMainApplicationClass() 方法,获得是调用了哪个 #main(String[] args) 方法,代码如下:

    private Class<?> deduceMainApplicationClass() {
        try {
        // 获得当前 StackTraceElement 数组 StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) {
          // 判断哪个执行了 main 方法 if ("main".equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; }

此处对应的就是我们Demo的启动类,DemoApplication,到处我们SpringApplication创建完成。代码不是很复杂,主要部分是加载META-INF/spring.factories里面的资源并实例化。

上一篇:Springboot漫游日志(6)


下一篇:不懂SpringApplication生命周期事件?那就等于不会Spring Boot嘛