Spring Boot到底是怎麼執行的,你知道嗎?

程式設計師私房菜發表於2019-04-17

Spring Boot到底是怎麼執行的,你知道嗎?

導讀

Spring Boot方式的專案開發已經逐步成為Java應用開發領域的主流框架,它不僅可以方便地建立生產級的Spring應用程式,還能輕鬆地透過一些註解配置與目前比較流行的微服務框架SpringCloud快速地整合。

在我們實際使用Spring Boot進行專案開發的過程中,往往只需要幾個很簡單的註解配置就能夠將應用啟動執行了,相比於傳統的Spring專案而已,這種提升大大地提高了我們的研發效率。然而,這種便捷性則是透過高度地上層封裝來實現的,如:“大量的註解封裝、約定大於配置的原則“等手段。所以,也許你已經使用Spring Boot開發很多個專案了,但對Spring Boot的執行原理真的搞清楚了嗎?如果,面試中有人問你Spring Boot的實現原理是什麼?你能正確地回答出來嗎?

與大部分其他框架及技術的使用場景一樣,我們往往過多地專注於使用層面,以便快速地完成業務開發,卻往往忽略了對框架底層執行原理的關注,所以面試中被懟也就不足為奇了。不過沒關係,在今天的文章中,小碼哥將為大家全方位地梳理下Spring Boot的底層執行原理,並透過圖文結合的方式給大家進行展示,希望對您的工作或者面試能夠有所幫助!

Spring Boot執行原理

實際上Spring Boot並不是要替代Spring框架,我們知道在JDK1.5推出註解功能以後,Spring框架實現了大量的註解來替代原有的基於XML的配置,主要用於配置管理、Bean的注入以及AOP等相關功能的實現。然而,隨著Spring註解的數量越來越多,並且被大量的使用,尤其是相同的多個註解會被大量重複地用到各個類或者方法中。這樣就導致了繁瑣的配置及大量冗餘的程式碼

到這裡你也許就會想到既然這麼多Spring註解很繁瑣,那麼可不可以將其組合一下呢?透過定義一些新的註解,將功能進行分類,不同的Spring註解透過新的註解定義進行一定的組合,這樣對於大部分通用場景下,只需要引入一個新的註解,就自動包含了與之相關的其他Spring註解?沒錯!Spring Boot說到底就是這麼個玩意

但是,要實現註解的組合並不是簡單的把多個註解牽強的疊加在一起,這裡涉及到一些程式語言上的實現,例如要組合一個註解,那麼該註解是否支援註解到別的註解上呢(略微有點拗口)?還有如果組合註解後,因為註解的背後還涉及到Spring容器上下文的初始化以及Bean注入相關的邏輯,如果一個A註解涉及的Bean,涉及到另外一個B註解涉及到的Bean的初始化;也就意味著A註解的Bean初始化,需要在B註解的Bean初始化完成後才能進行注入,否則就會導致Bean依賴注入的失敗。

Spring Boot框架本質上就是透過組合註解的方式實現了諸多Spring註解的組合,從而極大地簡化了Spring框架本身的繁瑣配置,實現快速的整合和開發。只是要這樣實現,也需要一定的基礎條件

元註解

說到底Spring Boot框架是在Spring框架的基礎上做了一層二次封裝,最重要的特點就是Spring Boot框架定義了一些新的註解來實行一些Spring註解的組合,而Spring註解則是基於JDK1.5+後的註解功能的支援來完成的。

關於JDK的註解如果想要註解到別的註解上,就需要將其定義為元註解,所謂的元註解,就是可以註解到其他註解上的註解,被註解的註解就是我們上面說到的組合註解。而Spring框架的很多註解都是可以作為元註解的,並且Spring框架本身也實現了很多組合註解,例如我們常用的@Configuration就是一個這樣的組合註解。因此,有了這樣一個條件Spring Boot的實現才有了基礎條件!

條件註解@Conditional

Spring 4提供了一個通用的基於條件的註解@Conditional。該註解可以根據滿足某一個特定條件與否來決定是否建立某個特定的Bean,例如,某個依賴包jar在一個類路徑的時候,自動配置一個或多個Bean時,可以透過@Conditional註解來實現只有某個Bean被建立時才會建立另外一個Bean,這樣就可以依據特定的條件來控制Bean的建立行為,這樣的話我們就可以利用這樣一個特性來實現一些自動的配置。

這一點對於Spring Boot實現自動配置來說是一個核心的基礎能力,從本質上來說Spring Boot之所以可以實現自動註解配置很大程度上也是基於這一能力。在Spring Boot中以@Conditional為元註解又重新定義了一組針對不同場景的組合條件註解,它們分別是:

  • @ConditionalOnBean:當容器中有指定Bean的條件下進行例項化。

  • @ConditionalOnMissingBean:當容器裡沒有指定Bean的條件下進行例項化。

  • @ConditionalOnClass:當classpath類路徑下有指定類的條件下進行例項化。

  • @ConditionalOnMissingClass:當類路徑下沒有指定類的條件下進行例項化。

  • @ConditionalOnWebApplication:當專案是一個Web專案時進行例項化。

  • @ConditionalOnNotWebApplication:當專案不是一個Web專案時進行例項化。

  • @ConditionalOnProperty:當指定的屬性有指定的值時進行例項化。

  • @ConditionalOnExpression:基於SpEL表示式的條件判斷。

  • @ConditionalOnJava:當JVM版本為指定的版本範圍時觸發例項化。

  • @ConditionalOnResource:當類路徑下有指定的資源時觸發例項化。

  • @ConditionalOnJndi:在JNDI存在的條件下觸發例項化。

  • @ConditionalOnSingleCandidate:當指定的Bean在容器中只有一個,或者有多個但是指定了首選的Bean時觸發例項化。

縱觀Spring Boot的一些核心註解,基於@Conditional元註解的組合註解就佔了很大部分,所以Spring Boot的核心功能基於就是這些註解實現的。在Spring Boot原始碼專案“spring-boot-autoconfigure”中,隨意開啟一個AutoConfiguration檔案,我們都會看到有上述條件註解的使用。如:

@Configuration
@ConditionalOnClass(DSLContext.class)
@ConditionalOnBean(DataSource.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class,
        TransactionAutoConfiguration.class })
public class JooqAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public DataSourceConnectionProvider dataSourceConnectionProvider(
            DataSource dataSource)
 
{
        return new DataSourceConnectionProvider(
                new TransactionAwareDataSourceProxy(dataSource));
    }

    @Bean
    @ConditionalOnBean(PlatformTransactionManager.class)
    public SpringTransactionProvider transactionProvider(
            PlatformTransactionManager txManager)
 
{
        return new SpringTransactionProvider(txManager);
    }
    ....
}


Spring Boot執行原理

在前面的篇幅中我們重點闡述了為什麼Spring Boot可以實現高度地自動化配置。那麼,接下來我們就結合Spring Boot最核心的組合註解@SpringBootApplication來分析下Spring Boot的專案到底是怎麼啟動執行的。

Spring Boot到底是怎麼執行的,你知道嗎?

@SpringBootApplication註解實際上是一個組合註解,除了對應用開放的@ComponentScan註解(實現對開發者自定義的應用包掃描)外,其最核心的註解就是@EnableAutoConfiguration,該註解表示開啟自動配置功能,而在具體的實現上則是透過匯入@Import(EnableAutoConfigurationImportSelector.class)類的例項,在邏輯上實現了對所依賴的核心jar下META-INF/spring.factories檔案的掃描,該檔案則宣告瞭有哪些自動配置需要被Spring容器載入,從而Spring Boot應用程式就能自動載入Spring核心容器配置,以及其他依賴的專案元件配置,從而最終完成應用的自動初始化,透過這種方法就向開發者遮蔽了啟動載入的過程。

如“spring-boot-autoconfigure”核心包中的META-INF/spring.factories檔案就是定義了需要載入的Spring Boot專案所依賴的基礎配置類,如Spring的容器初始化配置類等。如:

# Initializers
org.springframework.context.ApplicationContextInitializer=
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=
org.springframework.boot.autoconfigure.BackgroundPreinitializer

.....


而對於大部分第三方需要與Spring Boot整合的框架,或者我們日常開發中需要進行抽象的公共元件而言,得益於這種機制,也可以很容易地定製成開箱即用的各種Starter元件。而使用這些元件的使用者,往往只需要將依賴引入就好,不再需要進行任何額外的配置了!


Spring Boot後記


以上就是Spring Boot執行的基本原理了,希望這篇文章能夠對你有所幫助!實際上學習Spring Boot進行專案開發關鍵就是要掌握各種Spring及Spring Boot的各種註解,特別是一些關鍵核心註解。同樣在進行基於Spring Cloud微服務的開發中,也是需要理解Spring Cloud相關元件所提供的各種核心註解,只有這樣才能更好的理解框架的原理及使用,而不只是雲裡霧裡地進行各種似懂非懂的Copy開發。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31558358/viewspace-2641682/,如需轉載,請註明出處,否則將追究法律責任。

相關文章