美文网首页Spring框架原理
Spring Boot启动-构建SpringApplicatio

Spring Boot启动-构建SpringApplicatio

作者: 王勇1024 | 来源:发表于2019-02-23 14:49 被阅读1次

    构造方法

    下面是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启动-构建SpringApplicatio

        本文链接:https://www.haomeiwen.com/subject/emiuyqtx.html