Spring Boot启动-构建SpringApplication

构造方法

下面是SpringApplication的构造方法:

public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        // 第一步:推断Web应用类型
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        // 第二步:设置ApplicationContextInitializer
        setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));
        // 第三步:设置ApplicationListener
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        // 第四步:推断主类
        this.mainApplicationClass = deduceMainApplicationClass();
    }

从构造方法中可以看到,SpringApplication的构建过程主要包含三步:
第一步:推断Web应用类型
第二步:设置ApplicationContextInitializer
第三步:设置ApplicationListener
第四步:推断主类
下面我们就分别讲解一个这四个步骤。

第一步:推断Web应用类型

public enum WebApplicationType {
    // 不需要在web容器的环境下运行,也就是普通的工程
    NONE,
    // 基于servlet的Web项目
    SERVLET,
    // 响应式web应用==reactive web Spring5版本的新特性
    REACTIVE;
}

判断的方式也很简单:

  1. 如果Classpath中包含org.springframework.web.reactive.DispatcherHandler,并且不包含org.springframework.web.servlet.DispatcherServlet和org.glassfish.jersey.servlet.ServletContainer,则认为是REACTIVE类型;
  2. 如果不包含javax.servlet.Servlet或org.springframework.web.context.ConfigurableWebApplicationContext,则为NONE类型。
  3. 否则为SERVLET类型。
    如果想要手动指定Web应用类型,可以通过下面的方式实现:
public static void main(String[] args) {
    new SpringApplicationBuilder(HelloApplication.class)
        .web(WebApplicationType.NONE)
        .run(args);
}

第二步:设置ApplicationContextInitializer

设置ApplicationContextInitializer是通过SpringFactoriesLoader读取spring.factories文件的配置实现的,具体流程参见Spring Factories
在获取到对应的factory类名之后,会调用factory类默认的构造方法对其进行实例化。首先判断factoryName对应的类是否派生自目标类,如果是,则调用其默认的构造函数实例化,否则抛出IllegalArgumentException异常。
到这一步我们可以得到一些启示:如果我们想要创建一个jar包,并且想在Spring Boot项目启动时,自动完成jar包的一些初始工作,就可以在META-INF/spring.factories文件中配置我们自定义的factory类。这就是Spring starter的基本原理。
如果我们想监听Spring生命周期的相关事件,也可以实现自定义的ApplicationListener。

第三步:设置ApplicationListener

设置ApplicationListener的方式与上面相同。

第四步:推断主类

推断主类的实现代码如下:

    private Class deduceMainApplicationClass() {
        try {
            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;
    }

遍历整个堆栈,找到第一个包含main方法的类,即是主类

你可能感兴趣的:(Spring Boot启动-构建SpringApplication)