• SpringBoot启动过程分析


      我们知道,SpringBoot程序的启动很简单,代码如下:

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

      调用SpringApplication的静态方法run,这个run方法会构造一个SpringApplication实例,然后这调用这个实例的run方法就能启动SpringBoot程序,因此如果要分析SpringBoot程序的启动过程,我们就要先分析SpringApplication实例的构造过程以及run方法的执行过程。

    SpringApplication的构造过程

      下面是SpringApplication的静态run方法的源码,从源码可以得知,在执行SpringApplication的run方法的时候,先创建SpringApplication实例,然后载调用实例的run方法。

    1 public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
    2         return new SpringApplication(sources).run(args);
    3 }

      在SpringApplication的构造函数中,调用私有的initialize方法,initialize方法的定义如下:

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private void initialize(Object[] sources) {
        if (sources != null && sources.length > 0) {
            this.sources.addAll(Arrays.asList(sources));
        }
        //判断是否是web程序,并设置到webEnvironment属性中
        this.webEnvironment = deduceWebEnvironment();
        //从spring.factories文件中找出key为ApplicationContextInitializer的类并实例化后设置到SpringApplication的initializers属性中。这个过程也就是找出所有的应用程序初始化器
        setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));
              // 从spring.factories文件中找出key为ApplicationListener的类并实例化后设置到SpringApplication的listeners属性中。这个过程就是找出所有的应用程序事件监听器
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        找出main函数所在类
        this.mainApplicationClass = deduceMainApplicationClass();
    }

      getSpringFactoriesInstances最终的定义为:

    private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
            Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        // Use names and ensure unique to protect against duplicates
        Set<String> names = new LinkedHashSet<String>(
                //从META-INF/spring.factories文件中取出type类型的所有类名
                SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        //实例化得到的类
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
                classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }

    默认情况下,initialize方法从spring.factories文件中找出的key为ApplicationContextInitializer的类有:

    0 = "org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer"
    1 = "org.springframework.boot.context.ContextIdApplicationContextInitializer"
    2 = "org.springframework.boot.context.config.DelegatingApplicationContextInitializer"
    3 = "org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer"
    4 = "org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer"
    5 = "org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer"

    key为ApplicationListener的有:

    0 = "org.springframework.boot.ClearCachesApplicationListener"
    1 = "org.springframework.boot.builder.ParentContextCloserApplicationListener"
    2 = "org.springframework.boot.context.FileEncodingApplicationListener"
    3 = "org.springframework.boot.context.config.AnsiOutputApplicationListener"
    4 = "org.springframework.boot.context.config.ConfigFileApplicationListener"
    5 = "org.springframework.boot.context.config.DelegatingApplicationListener"
    6 = "org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener"
    7 = "org.springframework.boot.logging.ClasspathLoggingApplicationListener"
    8 = "org.springframework.boot.logging.LoggingApplicationListener"
    9 = "org.springframework.boot.autoconfigure.BackgroundPreinitializer"

    SpringApplication的执行

      在分析SpringApplication的run方法之前,先来看一下SpringApplicationRunListeners和SpringApplicationRunListener。SpringApplicationRunListeners内部持有一个SpringApplicationRunListener的集合,用于SpringApplicationRunListener监听的批量执行。SpringApplicationRunListener用于监听SpringApplication的run方法的执行。他定义了5个方法,代码如下:

    public interface SpringApplicationRunListener {
    
        /**
         *run方法执行的时候立马执行;对应事件的类型是ApplicationStartedEvent
         */
        void starting();
    
        /**
         * ApplicationContext创建之前并且环境信息准备好的时候调用;对应事件的类型是ApplicationEnvironmentPreparedEvent
         */
        void environmentPrepared(ConfigurableEnvironment environment);
    
        /**
         * ApplicationContext创建好并且在source加载之前调用一次;没有具体的对应事件
         */
        void contextPrepared(ConfigurableApplicationContext context);
    
        /**
         * ApplicationContext创建并加载之后并在refresh之前调用;对应事件的类型是ApplicationPreparedEvent
         */
        void contextLoaded(ConfigurableApplicationContext context);
    
        /**
         *run方法结束之前调用;对应事件的类型是ApplicationReadyEvent或ApplicationFailedEvent
         */
        void finished(ConfigurableApplicationContext context, Throwable exception);
    }

      SpringApplicationRunListener目前只有一个实现类EventPublishingRunListener,它把监听的过程封装为SpringApplicationEvent,并通过自身的SimpleApplicationEventMulticaster属性把时间multicast出去,广播出去的事件对象会被SpringApplication中的listeners属性进行处理。所以说SpringApplicationRunListener和ApplicationListener之间的关系是通过ApplicationEventMulticaster广播出去的SpringApplicationEvent所联系起来的。

      下面我们看一下SpringApplication的run方法的源码:

    public ConfigurableApplicationContext run(String... args) {
        //开始任务执行时间监听器
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        FailureAnalyzers analyzers = null;
        //设置系统属性『java.awt.headless』,为true则启用headless模式支持
        configureHeadlessProperty();
        //通过*SpringFactoriesLoader*检索*META-INF/spring.factories*,
            //找到声明的所有SpringApplicationRunListener的实现类并将其实例化,
            //之后逐个调用其starting()方法,广播SpringBoot要开始执行了。
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
             //创建并配置当前SpringBoot应用将要使用的Environment(包括配置要使用的PropertySource以及Profile),
                    //并遍历调用所有的SpringApplicationRunListener的environmentPrepared()方法,广播Environment准备完毕。
            ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
            //决定是否打印Banner
            Banner printedBanner = printBanner(environment);
            //根据webEnvironment的值来决定创建何种类型的ApplicationContext对象
                   //如果是web环境,则创建org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext
                    //否则创建org.springframework.context.annotation.AnnotationConfigApplicationContext
            context = createApplicationContext();
            //注册异常分析器
            analyzers = new FailureAnalyzers(context);
            //为ApplicationContext加载environment,之后逐个执行ApplicationContextInitializer的initialize()方法来进一步封装ApplicationContext,
                 //并调用所有的SpringApplicationRunListener的contextPrepared()方法,【EventPublishingRunListener只提供了一个空的contextPrepared()方法】,
                //之后初始化IoC容器,并调用SpringApplicationRunListener的contextLoaded()方法,广播ApplicationContext的IoC加载完成,
                //这里就包括通过**@EnableAutoConfiguration**导入的各种自动配置类。
            prepareContext(context, environment, listeners, applicationArguments,printedBanner);
            //初始化所有自动配置类,调用ApplicationContext的refresh()方法
            refreshContext(context);
            //遍历所有注册的ApplicationRunner和CommandLineRunner,并执行其run()方法。
                    //该过程可以理解为是SpringBoot完成ApplicationContext初始化前的最后一步工作,
                    //我们可以实现自己的ApplicationRunner或者CommandLineRunner,来对SpringBoot的启动过程进行扩展。
            afterRefresh(context, applicationArguments);
            //调用所有的SpringApplicationRunListener的finished()方法,广播SpringBoot已经完成了ApplicationContext初始化的全部过程。
            listeners.finished(context, null);
            //关闭任务执行时间监听器
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
            }
            return context;
        }
        catch (Throwable ex) {
            //调用异常分析器打印报告,调用所有的SpringApplicationRunListener的finished()方法将异常信息发布出去
            handleRunFailure(context, listeners, analyzers, ex);
            throw new IllegalStateException(ex);
        }
    }

    SpringBoot的启动过程,实际上就是对ApplicationContext的初始化过程。
    ApplicationContext创建后立刻为其设置Environmen,并由ApplicationContextInitializer对其进一步封装。
    通过SpringApplicationRunListener在ApplicationContext初始化过程中各个时点发布各种广播事件,并由ApplicationListener负责接收广播事件。
    初始化过程中完成IoC的注入,包括通过@EnableAutoConfiguration导入的各种自动配置类。
    初始化完成前调用ApplicationRunner和CommandLineRunner的实现类。

      

  • 相关阅读:
    Python入门-函数进阶
    Python入门-初始函数
    Leetcode300. Longest Increasing Subsequence最长上升子序列
    Leetcode139. Word Break单词拆分
    Leetcode279. Perfect Squares完全平方数
    Leetcode319. Bulb Switcher灯泡开关
    Leetcode322. Coin Change零钱兑换
    二叉树三种遍历两种方法(递归和迭代)
    Leetcode145. Binary Tree Postorder Traversal二叉树的后序遍历
    Leetcode515. Find Largest Value in Each Tree Row在每个树行中找最大值
  • 原文地址:https://www.cnblogs.com/senlinyang/p/8531001.html
Copyright © 2020-2023  润新知