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


先看示例

SpringBoot的啟動很簡單,在許多情況下,你可以委托給靜態SpringApplication.run方法,代碼如下:

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

從代碼上可以看出,調用了SpringApplication的靜態方法run。這個run方法會構造一個SpringApplication的實例,然后再調用這里實例的run方法就表示啟動SpringBoot。

當你的應用程序啟動時,你應該看到類似於以下輸出的內容:

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

因此,想要分析SpringBoot的啟動過程,我們需要熟悉SpringApplication的構造過程以及SpringApplication的run方法執行過程即可。

我們以上述這段代碼為例,分析SpringBoot的啟動過程。

一、SpringApplication的構造過程

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

    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的構造中,涉及到的幾個類:

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

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

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

       

1.2、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

二、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);
        }
    }
 
            
⑥-1、注冊異常分析器
    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());
        }
    }
 
            
⑥-2、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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM