zoukankan      html  css  js  c++  java
  • 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的实现类。

      

  • 相关阅读:
    【转】sublime text 2中Emmet插件8个常用的技巧
    程序猿崛起3——这一次,我用行动说话
    《Effective Java》学习笔记——积累和激励
    程序猿崛起2——互联网时代下的新潮流和新活法
    【非技术】做好属于自己的作品,然后让世界所有人都记住你
    【非技术】实现理想的第一步就是做自己
    【原创】程序猿崛起
    人生苦短,我用python——当我在玩python的时候我玩些什么
    一个新人如何学习在大型系统中添加新功能和Debug
    一个应届毕业生入职30天后的工作总结——作息
  • 原文地址:https://www.cnblogs.com/senlinyang/p/8531001.html
Copyright © 2011-2022 走看看