品Spring:SpringBoot和Spring到底有沒有本質的不同?

  • 2019 年 10 月 3 日
  • 筆記

現在的Spring相關開發都是基於SpringBoot的。

最後在打包時可以把所有依賴的jar包都打進去,構成一個獨立的可執行的jar包。如下圖13:


使用java -jar命令就可以運行這個獨立的jar包。如下圖14:


這個jar包的執行入口就是一個main函數,典型的格式如下:

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


從程式碼中可以得知,SpringApplication這個類就是SpringBoot的總入口。

以上這些內容,早已是路人皆知的事情了,這裡只是再贅述一遍


進入SpringApplication這個類的源碼里,首先看到的就是幾個application context所使用的類。

首先是AnnotationConfigApplicationContext,這是基於註解的非web應用使用的類,它是spring-context裡面的類,現在也用於SpringBoot中。

這表明對於非web應用來說,採用傳統的Spring構建,或是採用現在的SpringBoot構建,核心部分並沒有什麼本質區別。畢竟連類都是用的同一個。


再看就是AnnotationConfigServletWebServerApplicationContext,這是基於註解的web應用使用的類,注意,這個類是SpringBoot里的類

其實大家都知道,在還沒有SpringBoot時,基於傳統Spring構建web應用時使用的是AnnotationConfigWebApplicationContext這個類。

這個類位於spring-web中,顯然它是Spring裡面的類。(註:本文中所說的Spring指的是SpringFramework)

這裡有一個問題,不知你是否發現,從Spring到SpringBoot,非web應用使用的類沒有變,web應用使用的類改變了,為啥呢?


這個問題其實很簡單,從它們的啟動方式的差異就能很好的說明。

傳統Spring構建的web應用,會打成一個war包,放入tomcat下面。

先啟動tomcat,然後tomcat再去載入它下面的web應用(即war包)。

SpringBoot構建的web應用,會打成一個jar包,採用內嵌的tomcat。

先啟動jar包,會進入SpringBoot中,然後再去啟動tomcat。

因為現在SpringBoot要來負責啟動和停止web server,這和傳統Spring完全不同,所以它要自己實現一個web application context所使用的類。

由此我們可以推斷出,這個類里一定有關於web server啟動和停止的相關內容。


再來觀察一個細節,沒錯,就是類名稱。

傳統Spring使用的類名稱可以提煉出一個關鍵詞,就是Web。SpringBoot使用的類名稱可以提煉出的關鍵詞是ServletWebServer

前者只有Web,說明只關注web的問題,後者除了Web外還有Server,說明除了關注web外還要關注伺服器,即tomcat、jetty等這些web伺服器。

由此可見,從類名稱上的解釋和剛剛從啟動方式上的解釋是吻合的,是一致的。

這也說明,“時刻關注細節,你將發現更多”。這句話不僅可以用在工作當中,亦可以用在學習中、生活中。


細心的同學又會發現,後者中還有一個Servlet呢,這又怎麼解釋呢?

這說明這個WebServer是基於Servlet實現的。難道還有不是基於Servlet的嗎?有啊,那就是基於Reactive(響應式或反應式)的。

響應式使用的類是這個AnnotationConfigReactiveWebServerApplicationContext。可以仔細對比一下名字。

Spring從5.x引入了響應式編程。這裡不做深入討論,需要的話可以去看“編程新說”這個號之前的文章。


接著我們去源碼里看看,來證實一下我們的猜想。進入ServletWebServerApplicationContext類,就是剛剛那個類的父類。

首先它定義了一個WebServer,如下圖01:


其次又創建了這個WebServer,如下圖02:


接著又啟動了這個WebServer,如下圖03:


最後又關閉和釋放了這個WebServer,如下圖04:


由此證明了我們的猜想,確實有關於web伺服器的“全套”操作。

現在SpringBoot翻身成了主人,它不僅可以啟停web伺服器,還可以選擇web伺服器,是用tomcat、jetty還是netty,都是可以配置的。爽吧。


Spring的核心就是IOC容器,容器所作的事情就是bean定義的註冊,bean的實例化、初始化、依賴的裝配,bean方法的調用,bean實例的銷毀。

我們先來看看bean定義的註冊吧。

首先看下傳統Spring的,也就是AnnotationConfigWebApplicationContext這個類的。

先定義兩個成員變數,存儲要註冊的類和要掃描的包,如下圖05:


然後又用兩個類AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner來負責註冊類和掃描包,如下圖0607:


最後就是具體的來執行註冊類和掃描包,如下圖08:



接著再看下SpringBoot的,也就是AnnotationConfigServletWebServerApplicationContext這個類的。

也是先定義兩個成員變數,和上面的如出一轍,如下圖09:


也是用相同的兩個類來負責處理,如下圖1011:


編程新說注
實例化時雖然調用的構造函數不同,但是最終執行的卻是相同的構造函數。

最終執行具體的處理也是相同的,如下圖12:


由此可以看出傳統Spring和SpringBoot在對待bean定義註冊這一塊,完全相同,沒有任何區別。

其實這很好理解,IOC容器這塊內容在Spring中已經發展的相當成熟了,是不會再有人輕易去修改它了。

因此SpringBoot和Spring在本質上沒什麼差別,注意這裡說的是本質。

由於SpringBoot的啟動方式是把自身提前把web伺服器移後(即採用內嵌web伺服器),所以這塊是額外新增的內容。

由於SpringBoot採用根據條件(condition)自動配置的方式(AutoConfiguration),所以這塊也是額外新增的內容。

這兩塊都是額外新增的內容,和傳統Spring基本沒啥關係。

因此在SpringBoot和Spring重疊的部分,其實本質沒啥區別。

 

(END)

 

>>> 品Spring系列文章 <<<

 

品Spring:帝國的基石

品Spring:bean定義上梁山

品Spring:實現bean定義時採用的“先進生產力”

品Spring:註解終於“成功上位”

品Spring:能工巧匠們對註解的“加持”

 

 

作者是工作超過10年的碼農,現在任架構師。喜歡研究技術,崇尚簡單快樂。追求以通俗易懂的語言解說技術,希望所有的讀者都能看懂並記住。下面是公眾號和知識星球的二維碼,歡迎關注!