SpringBoot源碼分析之SpringBoot的啓動過程

先看示例html

SpringBoot的啓動很簡單,在許多狀況下,你能夠委託給靜態SpringApplication.run方法,代碼以下:java

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

從代碼上能夠看出,調用了SpringApplication的靜態方法run。這個run方法會構造一個SpringApplication的實例,而後再調用這裏實例的run方法就表示啓動SpringBoot。git

當你的應用程序啓動時,你應該看到相似於如下輸出的內容:github

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::       (v1.5.10.RELEASE)

所以,想要分析SpringBoot的啓動過程,咱們須要熟悉SpringApplication的構造過程以及SpringApplication的run方法執行過程便可。web

咱們以上述這段代碼爲例,分析SpringBoot的啓動過程。spring

1、SpringApplication的構造過程

SpringApplication構造的時候內部會調用一個private方法initialize:springboot

    public SpringApplication(Object... sources) {
      initialize(sources); // sources目前是一個MyApplication的class對象
    }

    private void initialize(Object[] sources) {
      if (sources != null && sources.length > 0) {
        this.sources.addAll(Arrays.asList(sources)); // 把sources設置到SpringApplication的sources屬性中,目前只是一個MyApplication類對象
      }
      this.webEnvironment = deduceWebEnvironment(); // 判斷是不是web程序,若是(javax.servlet.Servlet和org.springframework.web.context.ConfigurableWebApplicationContext)都在當前的類加載器中,則爲true不然爲false,判斷結果設置到webEnvironment屬性中
      

// 從spring.factories文件中找出key爲ApplicationContextInitializer的類並實例化後設置到SpringApplication的initializers屬性中。這個過程也就是找出全部的應用程序初始化器 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class));
// 從spring.factories文件中找出key爲ApplicationListener的類並實例化後設置到SpringApplication的listeners屬性中。這個過程就是找出全部的應用程序事件監聽器 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 找出main類,這裏是MyApplication類 this.mainApplicationClass = deduceMainApplicationClass(); }

下面分別介紹下載SpringApplication的構造中,涉及到的幾個類:app

1.一、ApplicationContextInitializer,應用程序初始化器,作一些初始化的工做:less

    public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
        void initialize(C applicationContext);
    }

Springboot中目前有以下這些ContextInitializer,看截圖:ide

       

1.二、ApplicationListener,應用程序事件(ApplicationEvent)監聽器:

    public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
        void onApplicationEvent(E event);
    }

這裏的應用程序事件(ApplicationEvent)有:應用程序啓動事件(ApplicationStartedEvent)、失敗事件(ApplicationFailedEvent)、準備事件(ApplicationPreparedEvent)等。

應用程序事件監聽器跟監聽事件是綁定的。好比:

  • ConfigServerBootstrapApplicationListener只跟ApplicationEnvironmentPreparedEvent事件綁定,
  • LiquibaseServiceLocatorApplicationListener只跟ApplicationStartedEvent事件綁定,
  • LoggingApplicationListener跟全部事件綁定等。

默認狀況下,initialize方法從spring.factories文件中找出的key爲ApplicationContextInitializer的類有:

org.springframework.boot.context.config.DelegatingApplicationContextInitializer
org.springframework.boot.context.ContextIdApplicationContextInitializer
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer
org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer

key爲ApplicationListener的有:

org.springframework.boot.context.config.ConfigFileApplicationListener
org.springframework.boot.context.config.AnsiOutputApplicationListener
org.springframework.boot.logging.LoggingApplicationListener
org.springframework.boot.logging.ClasspathLoggingApplicationListener
org.springframework.boot.autoconfigure.BackgroundPreinitializer
org.springframework.boot.context.config.DelegatingApplicationListener
org.springframework.boot.builder.ParentContextCloserApplicationListener
org.springframework.boot.context.FileEncodingApplicationListener
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

2、SpringApplication的執行

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的實現類並將其實例化,
        //以後逐個調用其started()方法,廣播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();
            
            //⑥-1註冊異常分析器
            analyzers = new FailureAnalyzers(context);
            
            //⑥-2爲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);
        }
    }

相關的分析:

StopWatch,StopWatch相關見《Spring計時器StopWatch使用

分析run方法以前,先看一下SpringApplication中的一些事件和監聽器概念。

、首先是SpringApplicationRunListeners類和SpringApplicationRunListener類的介紹

  • SpringApplicationRunListeners類:
    SpringApplicationRunListeners內部持有SpringApplicationRunListener集合和1個Log日誌類。用於SpringApplicationRunListener監聽器的批量執行。
class SpringApplicationRunListeners {

    private final Log log;

    private final List<SpringApplicationRunListener> listeners;
  • SpringApplicationRunListener類:

    SpringApplicationRunListener看名字也知道用於監聽SpringApplication的run方法的執行。

              

    它定義了5個步驟:

    1.   started(run方法執行的時候立馬執行;對應事件的類型是ApplicationStartedEvent):通知監聽器,SpringBoot開始執行
    2.   environmentPrepared(ApplicationContext建立以前而且環境信息準備好的時候調用;對應事件的類型是ApplicationEnvironmentPreparedEvent):通知監聽器,Environment準備完成
    3.   contextPrepared(ApplicationContext建立好而且在source加載以前調用一次;沒有具體的對應事件):通知監聽器,ApplicationContext已經建立並初始化完成
    4.   contextLoaded(ApplicationContext建立並加載以後並在refresh以前調用;對應事件的類型是ApplicationPreparedEvent):通知監聽器,ApplicationContext已經完成IoC配置價值
    5.   finished(run方法結束以前調用;對應事件的類型是ApplicationReadyEvent或ApplicationFailedEvent):通知監聽器,SpringBoot啓動完成

        SpringApplicationRunListener目前只有一個實現類EventPublishingRunListener,它把監聽的過程封裝成了SpringApplicationEvent事件並讓內部屬性(屬性名爲multicaster)ApplicationEventMulticaster接口的實現類SimpleApplicationEventMulticaster廣播出去,廣播出去的事件對象會被SpringApplication中的listeners屬性進行處理。

因此說SpringApplicationRunListener和ApplicationListener之間的關係是經過ApplicationEventMulticaster廣播出去的SpringApplicationEvent所聯繫起來的。更多的spring事件知識見《ApplicationEvent事件機制源碼分析

 
③、SpringBoot的Environment的準備
    private ConfigurableEnvironment prepareEnvironment(
            SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
        // 建立SpringBoot的Environment,多是StandardServletEnvironment或者StandardEnvironment
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        //包括配置要使用的PropertySource以及Profile
        configureEnvironment(environment, applicationArguments.getSourceArgs());
        //遍歷調用全部的Environment的environmentPrepared方法,目前只有一個實現類EventPublishRunListener,即調用其multicastEvent,廣播事件
        listeners.environmentPrepared(environment);
        if (!this.webEnvironment) {
            //將給定環境轉換爲標準環境。若是環境已是一個標準環境,而不是ConfigurableWebEnvironment,則不執行轉換,而且不改變返回值。
            environment = new EnvironmentConverter(getClassLoader())
                    .convertToStandardEnvironmentIfNecessary(environment);
        }
        return environment;
    }
決定是否打印Banner
    private Banner printBanner(ConfigurableEnvironment environment) {
        //判斷是否開啓打印,若是沒有開啓,直接返回不執行下面的打印邏輯
        if (this.bannerMode == Banner.Mode.OFF) {
            return null;
        }
        //讀取banner文件
        ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader
                : new DefaultResourceLoader(getClassLoader());
        SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
                resourceLoader, this.banner);
        if (this.bannerMode == Mode.LOG) {
            return bannerPrinter.print(environment, this.mainApplicationClass, logger);
        }
        return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
    }
⑤建立ApplicationContext
    protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                //經過反射得到ApplicationContext的類信息
        // 若是是web程序,那麼構造org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext容器
            // 不然構造org.springframework.context.annotation.AnnotationConfigApplicationContext容器
                contextClass = Class.forName(this.webEnvironment
                        ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                        "Unable create a default ApplicationContext, "
                                + "please specify an ApplicationContextClass",
                        ex);
            }
        }
        //經過類的newInstance建立實例
        return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
    }

    public static <T> T instantiate(Class<T> clazz) throws BeanInstantiationException {
        Assert.notNull(clazz, "Class must not be null");
        if (clazz.isInterface()) {
            throw new BeanInstantiationException(clazz, "Specified class is an interface");
        }
        try {
            return clazz.newInstance();
        }
        catch (InstantiationException ex) {
            throw new BeanInstantiationException(clazz, "Is it an abstract class?", ex);
        }
        catch (IllegalAccessException ex) {
            throw new BeanInstantiationException(clazz, "Is the constructor accessible?", ex);
        }
    }
 
    
⑥-一、註冊異常分析器
    public FailureAnalyzers(ConfigurableApplicationContext context) {
        this(context, null);
    }

    FailureAnalyzers(ConfigurableApplicationContext context, ClassLoader classLoader) {
        Assert.notNull(context, "Context must not be null");
        this.classLoader = (classLoader == null ? context.getClassLoader() : classLoader);
        //經過反射,批量建立FailureAnalyzer,順序的放到list集合裏
        this.analyzers = loadFailureAnalyzers(this.classLoader);
        prepareFailureAnalyzers(this.analyzers, context);
    }

    //遍歷爲每一個FailureAnalyzer調用prepareAnalyzer
    private void prepareFailureAnalyzers(List<FailureAnalyzer> analyzers,
            ConfigurableApplicationContext context) {
        for (FailureAnalyzer analyzer : analyzers) {
            prepareAnalyzer(context, analyzer);
        }
    }
    //將Analyzer擁有的工廠賦值給上面新建立的Analyzer,提供給Analyzer實例的回調。
    //在填充普通bean屬性以後調用,但在初始化回調(如InitializingBean.afterPropertiesSet()或自定義init-method)以前調用。
    private void prepareAnalyzer(ConfigurableApplicationContext context,
            FailureAnalyzer analyzer) {
        if (analyzer instanceof BeanFactoryAware) {
            ((BeanFactoryAware) analyzer).setBeanFactory(context.getBeanFactory());
        }
    }
 
    
⑥-二、ApplicationContext的初始化(environment、initializer)
    private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        //爲context設置上面的Environment
        context.setEnvironment(environment);
        
        //在ApplicationContext中應用任何相關的後處理。子類能夠根據須要應用額外的處理。
        postProcessApplicationContext(context);
        
        //在刷新上下文以前,將全部的applicationcontextinitialalizer應用於上下文。這裏是遍歷執行全部的initialize()來進一步封裝ApplicationContext
        applyInitializers(context);
        
        //
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }

        // Add boot specific singleton beans
        context.getBeanFactory().registerSingleton("springApplicationArguments",
                applicationArguments);
        if (printedBanner != null) {
            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
        }

        // Load the sources
        Set<Object> sources = getSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        load(context, sources.toArray(new Object[sources.size()]));
        
        //調用SpringApplicationRunListener的contextLoaded()方法,廣播ApplicationContext的IoC加載完成
        listeners.contextLoaded(context);
    }
    
    //初始化器作的工做,好比ContextIdApplicationContextInitializer會設置應用程序的id;AutoConfigurationReportLoggingInitializer會給應用程序添加一個條件註解解析器報告等:
//在刷新上下文以前,將全部的applicationcontextinitialalizer應用於上下文。 protected void applyInitializers(ConfigurableApplicationContext context) { for (ApplicationContextInitializer initializer : getInitializers()) { Class<?> requiredType = GenericTypeResolver.resolveTypeArgument( initializer.getClass(), ApplicationContextInitializer.class); Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); initializer.initialize(context); } }
⑦refreshContext
Spring容器的刷新refresh方法內部會作不少不少的事情:好比BeanFactory的設置,BeanFactoryPostProcessor接口的執行、BeanPostProcessor接口的執行、自動化配置類的解析、條件註解的解析、國際化的初始化等等。這部份內容會在以後的文章中進行講解。
    private void refreshContext(ConfigurableApplicationContext context) {
        //刷新底層應用程序上下文
        refresh(context);
        
        //增長鉤子
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            }
            catch (AccessControlException ex) {
                // Not allowed in some environments.
            }
        }
    }
    
    //刷新底層應用程序上下文
    protected void refresh(ApplicationContext applicationContext) {
        Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
        ((AbstractApplicationContext) applicationContext).refresh();
    }
⑧遍歷全部註冊的ApplicationRunner和CommandLineRunner,並執行其run()方法
   protected void afterRefresh(ConfigurableApplicationContext context,
            ApplicationArguments args) {
        callRunners(context, args);
    }
    
    private void callRunners(ApplicationContext context, ApplicationArguments args) {
        List<Object> runners = new ArrayList<Object>();
        // 找出Spring容器中ApplicationRunner接口的實現類
        runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
        // 找出Spring容器中CommandLineRunner接口的實現類
        runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
        // 對runners進行排序
        AnnotationAwareOrderComparator.sort(runners);
        // 遍歷runners依次執行
        for (Object runner : new LinkedHashSet<Object>(runners)) {
            // 若是是ApplicationRunner,進行ApplicationRunner的run方法調用
            if (runner instanceof ApplicationRunner) {
                callRunner((ApplicationRunner) runner, args);
            }
            // 若是是CommandLineRunner,進行CommandLineRunner的run方法調用
            if (runner instanceof CommandLineRunner) {
                callRunner((CommandLineRunner) runner, args);
            }
        }
    }
⑨調用全部的SpringApplicationRunListener的finished()方法,廣播SpringBoot已經完成了ApplicationContext初始化的所有過程
 
    
    public void finished(ConfigurableApplicationContext context, Throwable exception) {
        for (SpringApplicationRunListener listener : this.listeners) {
            callFinishedListener(listener, context, exception);
        }
    }
    
    private void callFinishedListener(SpringApplicationRunListener listener,
            ConfigurableApplicationContext context, Throwable exception) {
        try {
            listener.finished(context, exception);
        }
        catch (Throwable ex) {
            if (exception == null) {
                ReflectionUtils.rethrowRuntimeException(ex);
            }
            if (this.log.isDebugEnabled()) {
                this.log.error("Error handling failed", ex);
            }
            else {
                String message = ex.getMessage();
                message = (message == null ? "no error message" : message);
                this.log.warn("Error handling failed (" + message + ")");
            }
        }
    }
    
    @Override
    public void finished(ConfigurableApplicationContext context, Throwable exception) {
        //建立springboot初始化完成事件
        SpringApplicationEvent event = getFinishedEvent(context, exception);
        if (context != null && context.isActive()) {
            //活動上下文
            context.publishEvent(event);
        }
        else {
            //非活動上下文沒有多播程序,直接使用initialMulticaster進行廣播
            if (context instanceof AbstractApplicationContext) {
                for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
                        .getApplicationListeners()) {
                    this.initialMulticaster.addApplicationListener(listener);
                }
            }
            if (event instanceof ApplicationFailedEvent) {
                this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
            }
            this.initialMulticaster.multicastEvent(event);
        }
    }
    
    private SpringApplicationEvent getFinishedEvent(
            ConfigurableApplicationContext context, Throwable exception) {
        //若是出錯了,返回ApplicationFailedEvent的事件
        if (exception != null) {
            return new ApplicationFailedEvent(this.application, this.args, context,
                    exception);
        }
        return new ApplicationReadyEvent(this.application, this.args, context);
    }
⑫調用異常分析器打印報告,調用全部的SpringApplicationRunListener的finished()方法將異常信息發佈出去
    private void handleRunFailure(ConfigurableApplicationContext context,
            SpringApplicationRunListeners listeners, FailureAnalyzers analyzers,
            Throwable exception) {
        try {
            try {
                handleExitCode(context, exception);
                listeners.finished(context, exception);
            }
            finally {
                reportFailure(analyzers, exception);
                if (context != null) {
                    context.close();
                }
            }
        }
        catch (Exception ex) {
            logger.warn("Unable to close ApplicationContext", ex);
        }
        ReflectionUtils.rethrowRuntimeException(exception);
    }
    
    private void handleExitCode(ConfigurableApplicationContext context,
            Throwable exception) {
        //根據Exception獲得退出碼
        int exitCode = getExitCodeFromException(context, exception);
        
        //若是exitCode不爲0,發佈ExitCodeEvent事件
        if (exitCode != 0) {
            if (context != null) {
                context.publishEvent(new ExitCodeEvent(context, exitCode));
            }
            SpringBootExceptionHandler handler = getSpringBootExceptionHandler();
            if (handler != null) {
                handler.registerExitCode(exitCode);
            }
        }
    }

這樣run方法執行完成以後。Spring容器也已經初始化完成,各類監聽器和初始化器也作了相應的工做。

總結

  • SpringBoot的啓動過程,實際上就是對ApplicationContext的初始化過程。

  • ApplicationContext建立後馬上爲其設置Environment,並由ApplicationContextInitializer對其進一步封裝。

  • 經過SpringApplicationRunListener在ApplicationContext初始化過程當中各個時點發布各類廣播事件,並由ApplicationListener負責接收廣播事件。

  • 初始化過程當中完成IoC的注入,包括經過@EnableAutoConfiguration導入的各類自動配置類。

  • 初始化完成前調用ApplicationRunner和CommandLineRunner的實現類。

SpringBoot啓動的時候,不論調用什麼方法,都會構造一個SpringApplication的實例,而後調用這個實例的run方法,這樣就表示啓動SpringBoot。

在run方法調用以前,也就是構造SpringApplication的時候會進行初始化的工做,初始化的時候會作如下幾件事:

  1. 把參數sources設置到SpringApplication屬性中,這個sources能夠是任何類型的參數。本文的例子中這個sources就是MyApplication的class對象
  2. 判斷是不是web程序,並設置到webEnvironment這個boolean屬性中
  3. 找出全部的初始化器,默認有5個,設置到initializers屬性中
  4. 找出全部的應用程序監聽器,默認有9個,設置到listeners屬性中
  5. 找出運行的主類(main class)

SpringApplication構造完成以後調用run方法,啓動SpringApplication,run方法執行的時候會作如下幾件事:

  1. 構造一個StopWatch,觀察SpringApplication的執行
  2. 找出全部的SpringApplicationRunListener並封裝到SpringApplicationRunListeners中,用於監聽run方法的執行。監聽的過程當中會封裝成事件並廣播出去讓初始化過程當中產生的應用程序監聽器進行監聽
  3. 構造Spring容器(ApplicationContext),並返回
    3.1 建立Spring容器的判斷是不是web環境,是的話構造AnnotationConfigEmbeddedWebApplicationContext,不然構造AnnotationConfigApplicationContext
    3.2 初始化過程當中產生的初始化器在這個時候開始工做
    3.3 Spring容器的刷新(完成bean的解析、各類processor接口的執行、條件註解的解析等等)
  4. 從Spring容器中找出ApplicationRunner和CommandLineRunner接口的實現類並排序後依次執行

例子

寫了一個例子用來驗證分析的啓動邏輯,包括自定義的初始化器、監聽器、ApplicationRunner和CommandLineRunner。

地址在:https://github.com/fangjian0423/springboot-analysis/tree/master/springboot-startup

相關文章
相關標籤/搜索