Spring Boot————Spring Boot启动流程分析

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】
免费领取10G资料包与项目实战视频资料

一、引言

Spring Boot 的启动虽然仅仅是执行了一个main方法,但实际上,运行流程还是比较复杂的,其中包含几个非常重要的事件回调机制。在实际生产开发中,有时候也会利用这些启动流程中的回调机制,做一些项目初始化的工作,比如内存初始化等。所以,学习Spring Boot启动流程非常重要。

二、启动流程概述

SpringApplication.run(Object, String…)方法的执行中包括以下一些关键步骤:

1、准备环境

  1. 执行ApplicationContextInitializer.initialize()
  2. 监听器SpringApplicationRunListener回调contextPrepared()
  3. 加载主配置类(启动类)定义信息
  4. 监听器SpringApplicationRunListener回调contextLoaded()

2、刷新启动IOC容器

  1. 扫描加载所有容器中的组件
  2. 从META-INF/spring.factories中获取所有的EnableAutoConfiguration组件

3、回调容器中所有的 ApplicationRunner 、CommandLineRunner 的 run() 方法

4、监听器 SpringApplicationRunListener 回调 finished()方法

三、详细流程剖析

Spring Boot的启动方法调用流程为两步:1、创建SpringApplication对象;2、执行run()方法

20191017100208\_1.png

这句代码是一个中间的调用过程,接下来,我们将深度讲解创建SpringApplication对象和执行run()方法具体都做了哪些工作。

1、创建SpringApplication对象

通过SpringApplication的构造器,调用initialize()方法,对SpringApplication中的一些属性初始化默认值,同时,从META-INF/spring.factories找到所有ApplicationContextInitializer和ApplicationListener保存起来。

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private void initialize(Object[] sources) {
        // 保存主配置类
        if (sources != null && sources.length > 0) {
            this.sources.addAll(Arrays.asList(sources));
        }
        // 判断当前应用是否为一个WEB应用
        this.webEnvironment = deduceWebEnvironment();
        // 从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer,然后保存起来
        setInitializers((Collection) getSpringFactoriesInstances(
        ApplicationContextInitializer.class));
        // 从类路径下找到META-INF/spring.factories配置的所有ApplicationListener
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        // 从多个主配置类中找到有main方法的主配置类
        this.mainApplicationClass = deduceMainApplicationClass();
    }

2、运行run(String…)方法

主要做了两件事:

  • 回调:ApplicationContextInitializer和SpringApplicationRunListener;
  • 回调:ApplicationRunner和CommandLineRunner。

详细流程注释如下:

    /**
     * Run the Spring application, creating and refreshing a new
     * {@link ApplicationContext}.
     * 
     * @param args
     *            the application arguments (usually passed from a Java main
     *            method)
     * @return a running {@link ApplicationContext}
     */
    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        FailureAnalyzers analyzers = null;
        configureHeadlessProperty();
        // 获取SpringApplicationRunListeners,从类路径下META-INF/spring-factories
        SpringApplicationRunListeners listeners = getRunListeners(args);
        // 循环所有的listener,回调starting()方法
        listeners.starting();
        try {
            // 封装命令行参数
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            /*
             * 准备环境:
             * 创建环境完成后回调SpringApplicationRunListener.environmentPrepared()方法,表示
             * 环境准备完成。
             */
            ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
            // 打印控制台的Spring 字符画
            Banner printedBanner = printBanner(environment);
            // 创建IOC容器:ApplicationContext;决定创建web IOC还是普通的IOC容器。
            context = createApplicationContext();
            // 创建错误分析对象
            analyzers = new FailureAnalyzers(context);
            /*
             * 准备上下文环境,将environment保存到IOC容器中; 而且applyInitializers(),
             * 回调之前保存的所有的applicationContextInitializer的initialize()方法;
             * 回调所有的SpringApplicationRunListener的contextPrepareded();最后回调
             * 所有的SpringApplicationRunListener的contextLoaded()方法
             */
            prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            /*
             * 刷新容器:IOC容器的初始化(扫描所有的配置类、@Bean等,加载并创建IOC容器中所有的组件。如果是web应用,
             * 还会创建嵌入式的tomcat),当执行完refreshContext()后,IOC容器即创建完毕
             */
            refreshContext(context);
            /*
             * 从IOC容器中获取所有的ApplicationRunner和CommandLineRunner,
             * 然后先回调ApplicationRunner 再回调 CommandLineRunner
             */
            afterRefresh(context, applicationArguments);
            // 所有的SpringApplicationRunListener回调finished()方法
            listeners.finished(context, null);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
            }
            // 整个Spring Boot应用启动完成后,返回IOC容器
            return context;
        } catch (Throwable ex) {
            handleRunFailure(context, listeners, analyzers, ex);
            throw new IllegalStateException(ex);
        }
    }

四、总结

Spring Boot 的启动流程是:

1、准备环境

2、刷新启动IOC容器

3、回调容器中所有的 ApplicationRunner 、CommandLineRunner 的 run() 方法

4、监听器 SpringApplicationRunListener 回调 finished()方法

在“详细启动流程” 中,已经将run()方法中实际执行流程用注释的方式标记出来了,里面的方法都通过调用的方式完成了一些特定的功能,最主要的是把握他们的执行顺序和完成内容,可以通过debug的方式,并观察控制台输出和参数内容来进行追踪学习。

综上,就是关于Spring Boot启动的完整流程,欢迎文末留言。


来源:[]()

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Spring Boot————Spring Boot启动流程分析

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏