1. 程式人生 > >SpringBoot的啟動

SpringBoot的啟動

multi ros 定義類 web lazy-init 單獨 gate 單例 nbu

主要是SpringApplication.run()方法,其中準備環境和刷新context裏有比較關鍵的部分
分析的項目是用的 gs-routing-and-filtering 下的complete/gateway-0.0.1-SNAPSHOT

1 獲取SpringApplicationRunListeners,廣播start事件

2 準備環境

3 打印spring的banner.

4.創建 AnnotationConfigEmbeddedWebApplicationContext

5 準備AnnotationConfigEmbeddedWebApplicationContext

6 刷新AnnotationConfigEmbeddedWebApplicationContext

7.刷新後進行的調用,主要是ApplicationRunner和CommandLineRunner

8.發布完成事件

2 準備環境

不監聽bootstrap context的ApplicationEnvironmentPreparedEvent,即environment的getPropertySources()裏有bootstrap就直接返回,否則就創建bootstrapServiceContext().

在準備環境時,如果沒有會創建一個bootstrap的context,並設置為應用context的父,一些bootstrap需要使用到的bean,在創建bootstrap context的時候的refresh裏會創建即實例化,bootstrap context類型為ConfigurableApplicationContext,創建完成後準備環境會返回StandardEnvironment,準備環境完成.

創建 ConfigurableApplicationContext   
ConfigurableApplicationContext context = bootstrapServiceContext (environment,event.getSpringApplication());

使用SpringApplicationBuilder.run()創建ConfigurableApplicationContext對象,這會再調用SpringApplication.run().這次prepareEnvironment會直接返回之前已創建的StandardEnvironment.

createApplicationContext()會創建 AnnotationConfigApplicationContext.

prepareContext()會調用applyInitializers()進行refresh之前的各種初始化操作.
  
監聽器發布AnnotationConfigApplicationContext的contextPrepared事件.
把bean加載到context裏,load幾個Configuration類.
refreshContext;
告訴子類刷新內部的BeanFactory,準備這個context使用的BeanFactory,設置beanFactory的回調,註冊resolvable依賴,註冊默認的環境beans.

factory processors註冊到context裏,註冊bean創建時的攔截器bean processors,初始化MessageSource.初始化ApplicationEventMulticaster.初始化其他的特別子類的特別的bean,註冊監聽器.實例化所有的剩余的(不是懶加載的)單例對象.完成refresh,初始化lifecycle processor,告訴lifecycle processor onRefresh,發布ContextRefreshedEvent事件.重置common introspection caches,因為單例對象可能再也用不到這些緩存的元數據.刷新後調用runners.調用SpringApplicationRunListeners完成事件.
設置bootstrap context成為應用context的一個父類.
廣播ApplicationEnvironmentPreparedEvent 事件.環境準備完畢

6 刷新AnnotationConfigEmbeddedWebApplicationContext

具體看AbstractApplicationContext.refresh(),掃描項目包裏用戶定義的.class文件,然後進行bean定義和實例化也在這一步裏面.spring裏有著大量的Listener,他們通過Multicaster來廣播某一個event來讓特殊的listener做指定的處理.

準備這個context使用的beanfactory

invokeBeanFactoryPostProcessors(beanFactory)調用工程處理器在context裏註冊為bean.掃描用戶配置的bean也是在這一步裏.
ConfigurationClassParser.processConfigurationClass(configurationClass);
遞歸處理ConfigurationClass,和它的父類.

ClassPathBeanDefinitionScanner.doScan()
掃描項目包,返回BeanDefinitionHolder.默認掃描的路徑是@SpringBootApplication的為根目錄.

這裏需要註意的是掃描class文件解析後生成的是BeanDefinition,有了這個就可以創建bean對象,但是此時對象並沒有生成.
最後發布ContextRefreshedEvent事件

刷新後重置spring通用緩存

發布ApplicationReadyEvent事件

AbstractApplicationContext.refresh()的代碼:

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                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...
                resetCommonCaches();
            }
        }
    }

BeanDefinition與Bean的一些概念:

BeanDefinition描述一個有屬性值,,有構造參數值,和提供給具體實現使用的進一步信息的bean實例.這只是一個最小化的接口:主要目的是允許比如PropertyPlaceholderConfigurer這樣的BeanFactoryPostProcessor來內省和修改屬性值和其他bean的元數據.
BeanWrapper:spring底層級別的javabean設施的的核心接口,通常不直接使用,會通過BeanFactory或者DataBinder來使用.

AttributeAccessor定義一個可以從任意對象裏獲取設置元數據的一般協議.

BeanMetadataElement一個bean的元數據元素用來實現攜帶一個configuration源對象.

AbstractBeanDefinition是具體的,完整的BeanDefinition類的基礎類.是GenericBeanDefinition,RootBeanDefinition和ChildBeanDefinition的分解公共屬性.

GenericBeanDefinition是一個一站式的標準bean定義.和任何bean定義一樣,它允許指定一個類加可選的構造參數值和屬性值.另外,通過`parentName`屬性從一個父bean定義獲取可以被靈活配置.總的來說,使用GenericBeanDefinition時為了註冊用戶可見的bean定義(一個post-processor可能對其操作,甚至有重新配置the parent name的可能).當父子關系預先決定了就可以使用RootBeanDefinition / ChildBeanDefinition . GenericBeanDefinition是自2.5以後新加入的bean文件配置屬性定義類,是ChildBeanDefinition和RootBeanDefinition更好的替代者.

RootBeanDefinition表示在運行時,一個支持在spring BeanFactory支持一個特定bean的合並的bean定義.它可能被多個源bean定義互相繼承中創建.典型地註冊為GenericBeanDefinition.根本上來說,在運行時一個RootBeanDefinition是一個統一的bean定義視圖

ChildBeanDefinition定義那些從父類繼承配置的bean.子bean定義對父bean定義有一個固定的依賴.

AnnotatedBeanDefinition暴露一個關於bean定義的類的註解元數據,在不要求類加載的情況下.

AnnotatedGenericBeanDefinition類繼承GenericBeanDefinition抽象類,通過實現AnnotatedBeanDefinition接口支持暴露註解元數據信息。 註意:GenericBeanDefinition 變體主要用於測試代碼(希望對AnnotatedBeanDefinition 進行操作),例如Spring組件的掃描支持的實現類(默認類是ScannedGenericBeanDefinition,通常也實現AnnotatedBeanDefinition接口).

ScannedGenericBeanDefinition這個類不早早的加載bean的類.它傾向於從".class"文件裏獲取所有相關的元數據,使用ASM ClassReader解析.它的功能和AnnotatedGenericBeanDefinition#AnnotatedGenericBeanDefinition(AnnotationMetadata)相同,但是被已經掃描過得類型bean和那些已經被別的註冊或者發現為其他意義的beans區分.

創建一個bean的過程

//運行Spring應用,創建和刷新一個新的ApplicationContext
SpringApplication.run();
SpringApplication.refreshContext();
//實例化並調用所有註冊的BeanFactoryPostPrcessor beans,如果有明確的順序就按順序來.必須在單例對象實例化之前調用.
AbstractApplicationContext.invokeBeanFactoryPostProcessors(beanFactory);
PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);
//構建和校驗一個基於註冊的Configuration類的配置模型
ConfigrationClassPostProcessor.processConfigBeanDefinitions(registry);
//通過從源類裏讀取註解,成員和方法來處理和構建一個完整的ConfigurationClass.當相關的源被發現時這個方法可以被調用多次,返回處理類的父類,沒有就返回null.
ConfigurationClassParser.doProcessConfigurationClass(configClass, sourceClass)
/**內部邏輯:(加載類定義的順序)
首先遞歸的處理所有的成員(包括內嵌的);
處理所有的@PropertySource註解;
處理所有的@ComponentScan註解;
處理所有的@Import註解;
處理所有的@ImportResource註解;
處理單獨的@Bean方法;
處理接口的默認方法;
如果有父類處理父類,發現父類就返回父類的註解元數據然後遞歸;
沒有父類就處理完成;
*/

//對指定的基礎包進行一個掃描,返回所有的註冊bean定義.這個方法不註冊任何註解配置處理器,把這留給調用者來處理.
ClassPathBeanDefinitionScanner.doScan(basePackages)
/**內部邏輯:
掃描包獲取候選的bean定義;
若是AbstractBeanDefinition,進一步的設置給的bean定義,超越從掃描的組件類裏獲取的內容;
若是AnnotatedBeanDefinition,把元數據裏的註解轉換成bean定義裏的設置;
校驗beanName是否和相關的bean定義需要註冊或者和一個已存在的定義有沖突.
創建bean定義的持有者;bean的持有者是否需要代理;註冊bean的持有者.
*/

//為候選的組件掃描類路徑(把org.springframework.context.annotation. ClassPathBeanDefinitionScanner 設置為trace可以輸出掃描的路徑,忽略的資源,設置為debug可以打印被認證的組件類或者被忽視的類)
ClassPathBeanDefinitionScanner.findCandidateComponents(basePackage)
/**
內部邏輯:
  //決定給的類是否匹配任何的排除過濾器或者至少匹配一個包含過濾器.
  ClassPathScanningCandidateComponentProvider.isCandidateComponet(metadataReader)
  //根據metadataReader描述的類,創建一個新的ScanneedGebericBeanDefinition.
  new ScannedGenericBeanDefinition(metadataReader)
  //決定被給的bean定義是否有作為候選的資格.默認的方法實現檢查了類是否是具體的(也就是非抽象或者接口).也檢查了被描述的類是否是獨立的類,也就是說是top-level類還是可以從封裝類裏被獨立構建的內嵌類(靜態內部類).
  ClassPathScanningCandidateComponentProvider. isCandidateComponet(AnnotatedBeanDefinition)
*/
 
//在當前的beanFactory裏找尋AspectJ註解的切面bean,返回一個Advisor的list來表示他們
BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors();

創建對象相關的調用方法

AbstractAutowireCapableBeanFactory.instantiateBean(beanName,mbd)

創建對象

AbstractAutowireCapableBeanFactory.initializeBean(beanName,bean,mbd)

初始化對象

AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(existingBean,beanName);創建完成之前的處理,會對Aware進行設置

DefaultListableBeanFactory.preInstantiateSingletons();

實例化所有剩余的單例bean

啟動tomcat

在AnnotationConfigEmbeddedWebApplicationContext刷新時會調用EmbeddedWebApplicationContext.onRefresh()的方法,這會創建容器,在這個項目裏就是創建一個內嵌的tomcat.tomcat啟動時會實例化ServletContextInitializer,在本項目中ZuulFilterInitializer就是一個ServletContextInitializer的子類.該類的初始化,會把ZuulFilter都實例化,包括項目中的SimpleFilter.

EmbeddedWebApplicationContext.createEmbeddedServletContainer();

ContainerBase.startInternal()
啟動這個組件,實現要求的接口
ContainerBase.findChildren()
找到這個容器關聯的子容器,把子容器放到另一個線程池裏執行
ContainerBase.StartChild.call();

調用子容器StandardEngine.start();

StandardHost.startInternal();

TomcatStarter.onStartup(classes,servletContext);
EmbeddedWebApplicationContext.getServletContextInitializerBeans()
 
獲取embedded Servlet context需要使用的ServletContextInitializer們
這裏會實例化類型為ServletContextListener的bean,所以ZuulFilterInitializer會在這裏被實例化.SimpleFilter會在Initializer裏被實例化.這是一些底層處理器的實例化時機,比普通的bean要實例化的早

springboot啟動小結

springboot裏我比較關心的就是對象是如何創建的.在refresh裏掃描class文件,轉換成beanDefinition.再在需要的時候實例化.實例化時,所依賴的對象會先實例化,這裏面經常會采用遞歸的方式來遍歷創建bean.最後再把一些沒有在初始化裏創建的bean通過finishBeanFactoryInitialization來創建.

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

SpringBoot的啟動