美文网首页
(1)SpringBoot源码: 启动类型推断

(1)SpringBoot源码: 启动类型推断

作者: 逆风踏雷 | 来源:发表于2020-05-04 18:31 被阅读0次

    1.启动类的调用链。

    典型的SpringBoot启动代码如下:

    ...
     public static void main(String[] args) throws InterruptedException {
            SpringApplication.run(ApplicationMain.class, args);
            //保证当前线程不会结束
            Thread.currentThread().join();
        }
    ...
    

    其实看SpringApplication 的类注释,为了在启动之前定制化SpringBoot的配置,也可以有如下写法:

      public static void main(String[] args) {
        SpringApplication application = new SpringApplication(MyApplication.class);
        // ... customize application settings here
        application.run(args)
     }
    

    那么问题来了,一种是静态方法,一种是构造方法,两种启动方式在原理上有啥区别吗?答案是: 没有,静态方法底层调用了构造方法,之所以常用静态方法,我推测是因为代码简洁。代码如下:

    public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
            return run(new Class<?>[] { primarySource }, args);
        }
    
    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
                    //看到了吧,就是这里用构造方法创建的,那构造方法都干了啥呢?
            return new SpringApplication(primarySources).run(args);
        }
    

    2.SpringApplication的构造

    先上代码

    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
                     //设置类加载器,默认为null,使用系统加载器
            this.resourceLoader = resourceLoader;
            Assert.notNull(primarySources, "PrimarySources must not be null");
                    //LinkedHashSet 可以保证元素唯一性以及插入顺序,这里是为了缓存我们自己指定的启动主类。
                    //TODO:为啥非要保证插入顺序?
            this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    //重点来了,这里可以推断出启动类型。
            this.webApplicationType = WebApplicationType.deduceFromClasspath();
            setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
            setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
            this.mainApplicationClass = deduceMainApplicationClass();
        }
    

    deduce意思是推断,进到这个方法里面:WebApplicationType.deduceFromClasspath();

    static WebApplicationType deduceFromClasspath() {
    //这里在尝试加载:DispatcherHandler,DispatcherServlet,ServletContainer。如果加载到了handler,但是没有加载到DispatcherServlet和jersey容器,就会判断是一个REACTIVE web工程(响应式)。
            if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
                    && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
                return WebApplicationType.REACTIVE;
            }
                  //这里试图加载:Servlet,ConfigurableWebApplicationContext,如果都没加载到那么判定为非web工程。
            for (String className : SERVLET_INDICATOR_CLASSES) {
                if (!ClassUtils.isPresent(className, null)) {
                    return WebApplicationType.NONE;
                }
            }
      //否则就是一个web工程
            return WebApplicationType.SERVLET;
        }
    

    综上,SpringBoot通过判断一些经典web类是否被加载来推断工程类型,因此如果不想使用SpringBoot的web功能,只需要不引入springboot-web依赖即可。

    相关文章

      网友评论

          本文标题:(1)SpringBoot源码: 启动类型推断

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