springboot啓動流程源代碼分析

在這裏插入圖片描述
springboot 的啓動入口是 SpringApplication run方法,代碼如下:

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            configureIgnoreBeanInfo(environment);
            Banner printedBanner = printBanner(environment);
          //此處創建 context
            context = createApplicationContext();
            exceptionReporters = getSpringFactoriesInstances(
                    SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
          //初始化context 的核心邏輯都在這行代碼裏。
            refreshContext(context);
            afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }
            listeners.started(context);
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, listeners);
            throw new IllegalStateException(ex);
        }

        try {
            listeners.running(context);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, null);
            throw new IllegalStateException(ex);
        }
        return context;
    }

再具體分析下 refreshContext的代碼邏輯

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
//清除緩存,並讀取配置文件裏的環境變量
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
                       // 此處的 bean factory 是通過父類GenericApplicationContext 初始化的 DefaultListableBeanFactory
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
// 配置 beanFactory, 包括註冊(第一次) BeanPostProcessor, 設置 classLoader等等。
// BeanPostProcessor 有兩個主要的方法:postProcessBeforeInitialization 和 postProcessAfterInitialization 。 
// 這個兩個方法分別的執行時期是 bean 初始化之前和初始化之後。具體的執行時期後面會說到

            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
//爲 applicationContext的子類註冊(第二次)個性化的 BeanPostProcessor
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
//執行 context 中註冊的 BeanFactoryPostProcessor中的postProcessBeanFactory() 方法,BeanFactoryPostProcessor只有這一個方法
//BeanFactoryPostProcessor 是 bean 屬性處理容器。即管理 bean工廠中的BeanDefinition, 
// BeanDefinition在 spring mvc 中就是 xml 文件中對應的 bean 標籤(注意,是標籤,而不是真實的 JAVA BEAN)。
//可以看到,此處已經 invoke 了postProcessBeanFactory() 方法。 而 BeanPostProcessor 的方法還沒有被調用,
//所以 BeanFactoryPostProcessor的執行是要早於BeanPostProcessor的。
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
//再次註冊BeanPostProcessor(這已經是第三次註冊,
// 第一註冊的是AbstractApplicationContext中用到的 processor, 
// 第二次爲ServletWebServerApplicationContext 註冊 processor)。
// 這次是爲實際用到的 context註冊 processor(spring boot 即是AnnotationConfigServletWebServerApplicationContext),
// 併爲根據優先級和 order 排序。
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
// 實例化並註冊 MessageSource類。MessageSource是國際化相關的接口
                initMessageSource();

                // Initialize event multicaster for this context.
//初始化spring 事件廣播器,ApplicationContext會通過廣播器發送事件,負責監聽廣播器的 listener 會負責處理事件
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
// 在一些特殊的 ApplicationContext子類中實例化一些特殊的 bean. 
//例如ServletWebServerApplicationContext(AnnotationConfigServletWebServerApplicationContext的父類)會初始化TomcatWebServer,
//並啓動這個 server,在 spring boot 工程中,相當於啓動了整個 spring boot 項目。
                onRefresh();

                // Check for listener beans and register them.
//爲ApplicationEventMulticaster註冊監聽 listener(ApplicationListener), 
//會有一些默認的 listener被註冊。例如這是一個 dubbo provider的工程,就會註冊DubboBannerApplicationListener 
// 同時也會有一些自定義的 listener.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
//終於到了初始 java bean 的階段, 注意此處只初始化單例的 bean, 並且非懶加載的類(默認即非懶加載)。
//雖然此時 java bean已經實例化,但是其依賴自動注入的 bean卻不再此時注入,而是等到用到的時候再去獲取,
//所以這裏不會出現循環依賴的問題。
// 一個 spring bean 的初始化過程如下:
//        1. 執行構造器
//        2. BeanPostProcessor的postProcessBeforeInitialization方法
//        3. InitializingBean的afterPropertiesSet方法
//        4,@Bean註解的initMethod方法
//        5,BeanPostProcessor的postProcessAfterInitialization方法
//        6,DisposableBean的destroy方法
//        7,@Bean註解的destroyMethod方法
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
//實例化LifecycleProcessor並執行其 onRefresh()方法,刷新上下文,啓動一些需要在初始化階段啓動的類(實現了Lifecycle接口的類)
// 發佈ContextRefreshedEvent事件,這個應該是表示上下文啓動完成的事件
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
//清理單例 bean 的元數據緩存。
                resetCommonCaches();
            }
        }
    }

至此, spring boot的啓動過程就完成了, 基於篇幅和時間問題。其中還有很多代碼細節沒有仔細分析,這些就留給未來吧。

整個過程分析下來發現這個啓動過程會有幾個核心接口(應該也是 spring 整個 ioc機制的核心接口)

BeanFactory
ApplicationContext
BeanPostProcessor
BeanFactoryPostProcessor
ApplicationEventMulticaster
BeanDefinition
LifecycleProcessor
以及每個接口裏面的方法及其執行時序。
弄清楚每一個接口的原理和具體使用場景,對我們使用和理解 spring 至關重要。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章