乐趣区

关于springboot:SpringApplication创建初始化流程

有两大步:①创立 spring 利用 ②把 spring 利用跑起来


一、创立SpringApplication

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

step into
应用 new class 把主程序类传进来,而后调用 run 办法

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

step into run 办法
第一步,创立 spring 利用。第二步把 spring 利用跑起来

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

step into

public SpringApplication(Class... primarySources) {
// 调用本类有参结构器,传入两个参数
        this((ResourceLoader)null, primarySources); 
}

step into this 办法
初始化了好多属性

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    // 第一个属性,资源加载器 resourceLoader 
    this.resourceLoader = resourceLoader;
    // 断言你有主配置类,如果没有,则报错
    Assert.notNull(primarySources, "PrimarySources must not be null"); 
    // 把主配置类信息保存起来,this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); 
    // 决定以后 web 利用的类型。如何决定的看上面的源码
    this.webApplicationType = WebApplicationType.deduceFromClasspath(); 
    //bootstrappers: 初始启动疏导器(我的项目一启动就要干什么)。如何获取的看上面的源码
    this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
    // 设置初始化器。只有看到 getSpringFactoriesInstances 这个办法,都是去 META-INF/spring.factories 文件中有没有配置某个类类,它的值是什么
    // 如果找到了 ApplicationContextInitializer,就会放到 List<ApplicationContextInitializer<?>> initializers 里
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 设置监听器。去 spring.factories 文件中有没有配置 ApplicationListener 类,它的值是什么
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // 找主程序。决定哪个是主程序。如何决定的看上面的源码剖析
    this.mainApplicationClass = deduceMainApplicationClass();}

如何决定以后 web 利用的类型??Servlet or 响应式编程?

static WebApplicationType deduceFromClasspath() {
    // 应用 ClassUtils 工具类判断以后零碎有没有导入 org.springframework.web.reactive.DispatcherHandler 响应式编程的申请处理器
    if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
    && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
      // 如果是响应式编程,相当于导入了 DispatcherHandler 类,就会返回它是一个响应式编程
      return WebApplicationType.REACTIVE;
    }
    // 如果是原生的 serlvet 编程
    for (String className : SERVLET_INDICATOR_CLASSES) {if (!ClassUtils.isPresent(className, null)) {return WebApplicationType.NONE;}
    }
    // 如果是原生的 serlvet 编程,就会返回它是一个原生的 serlvet 编程
    return WebApplicationType.SERVLET;
}

如何获取初始化启动器??

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {return getSpringFactoriesInstances(type, new Class<?>[] {});
}

// 进入 getSpringFactoriesInstances 办法
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    // 获取类的加载器
    ClassLoader classLoader = getClassLoader();
    //spring.factories 文件中找类型是 org.springframework.boot.Bootstrapper
    Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    // 如果没找到,即没人配置它。如果有,就会创立实例并返回
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

如何决定哪个是主程序???

private Class<?> deduceMainApplicationClass() {
    try {
    // 去堆栈里找哪个类是有 main 办法的,有 main 办法的就是主程序,主程序有很多,只有找到第一个有 main 办法的就行了
        StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
        for (StackTraceElement stackTraceElement : stackTrace) {if ("main".equals(stackTraceElement.getMethodName())) {return Class.forName(stackTraceElement.getClassName());
            }
        }
    }
    catch (ClassNotFoundException ex) {// Swallow and continue}
    return null;
}

创立 SpringApplication 小总结

保留一些信息。断定以后利用的类型。Servlet or 响应式编程
bootstrappers:初始启动疏导器(List<Bootstrapper>):去 spring.factories 文件中找 org.springframework.boot.Bootstrapper
找 ApplicationContextInitializer;去 spring.factories 找 ApplicationContextInitializer,保留在 List<ApplicationContextInitializer<?>> initializers
找 ApplicationListener 利用监听器。去 spring.factories 找 ApplicationListener,保留在 List<ApplicationListener<?>> listeners

简略来说,利用创立的过程,就是把一些要害的主键去 spring.factories 文件中给咱们把信息读取进去,提前保留到 springapplication 里
退出移动版