讀古今文學網 > Spring Boot實戰 > 2.2 使用起步依賴 >

2.2 使用起步依賴

要理解Spring Boot起步依賴帶來的好處,先讓我們假設它們尚不存在。如果沒用Spring Boot的話,你會向項目裡添加哪些依賴呢?要用Spring MVC的話,你需要哪個Spring依賴?你還記得Thymeleaf的Group和Artifact ID嗎?你應該用哪個版本的Spring Data JPA呢?它們放在一起兼容嗎?

看來如果沒有Spring Boot起步依賴,你就有不少功課要做。而你想要做的只不過是開發一個Spring Web應用程序,使用Thymeleaf視圖,通過JPA進行數據持久化。但在開始編寫第一行代碼之前,你得搞明白,要支持你的計劃,需要往構建說明裡加入哪些東西。

考慮再三之後(也許你還從其他有相似依賴的應用程序構建說明中複製粘貼了不少內容),你的Gradle構建說明裡大概會有下面這些東西:

compile(\"org.springframework:spring-web:4.1.6.RELEASE\")
compile(\"org.thymeleaf:thymeleaf-spring4:2.1.4.RELEASE\")
compile(\"org.springframework.data:spring-data-jpa:1.8.0.RELEASE\")
compile(\"org.hibernate:hibernate-entitymanager:jar:4.3.8.Final\")
compile(\"com.h2database:h2:1.4.187\")

  

這段依賴列表不錯,應該能正常工作,但你是怎麼知道的?你怎麼保證你選的這些版本能相互兼容?也許可以,但構建並運行應用程序之前你是不知道的。再說了,你怎麼知道這個列表是完整的?在一行代碼都沒寫的情況下,你離開始構建還有很長的路要走。

讓我們退一步再想想,我們要做什麼。我們要構建一個擁有如下功能的應用程序。

  • 這是一個Web應用程序。

  • 它用了Thymeleaf。

  • 它通過Spring Data JPA在關係型數據庫裡持久化數據。

如果我們只在構建文件裡指定這些功能,讓構建過程自己搞明白我們要什麼東西,豈不是更簡單?這正是Spring Boot起步依賴的功能。

2.2.1 指定基於功能的依賴

Spring Boot通過提供眾多起步依賴降低項目依賴的複雜度。起步依賴本質上是一個Maven項目對像模型(Project Object Model,POM),定義了對其他庫的傳遞依賴,這些東西加在一起即支持某項功能。很多起步依賴的命名都暗示了它們提供的某種或某類功能。

舉例來說,你打算把這個閱讀列表應用程序做成一個Web應用程序。與其向項目的構建文件裡添加一堆單獨的庫依賴,還不如聲明這是一個Web應用程序來得簡單。你只要添加Spring Boot的Web起步依賴就好了。

我們還想以Thymeleaf為Web視圖,用JPA來實現數據持久化,因此在構建文件裡還需要Thymeleaf和Spring Data JPA的起步依賴。

為了能進行測試,我們還需要能在Spring Boot上下文裡運行集成測試的庫,因此要添加Spring Boot的test起步依賴,這是一個測試時依賴。

統統放在一起,就有了這五個依賴,也就是Initializr在Gradle的構建文件裡提供的:

dependencies {
  compile \"org.springframework.boot:spring-boot-starter-web\"
  compile \"org.springframework.boot:spring-boot-starter-thymeleaf\"
  compile \"org.springframework.boot:spring-boot-starter-data-jpa\"
  compile \"com.h2database:h2\"
  testCompile(\"org.springframework.boot:spring-boot-starter-test\")
}

  

正如先前所見,添加這些依賴的最簡單方法就是在Initializr裡選中Web、Thymeleaf和JPA復選框。但如果在初始化項目時沒有這麼做,當然也可以稍後再編輯生成的build.gradle或pom.xml。

通過傳遞依賴,添加這四個依賴就等價於加了一大把獨立的庫。這些傳遞依賴涵蓋了Spring MVC、Spring Data JPA、Thymeleaf等內容,它們聲明的依賴也會被傳遞依賴進來。

最值得注意的是,這四個起步依賴的具體程度恰到好處。我們並沒有說想要Spring MVC,只是說想要構建一個Web應用程序。我們並沒有指定JUnit或其他測試工具,只是說我們想要測試自己的代碼。Thymeleaf和Spring Data JPA的起步依賴稍微具體一點,但這也只是由於沒有更模糊的方法聲明這種需要。

這四個起步依賴只是Spring Boot眾多起步依賴中的滄海一粟。附錄B羅列出了全部起步依賴,並簡要描述了一下它們向項目構建引入了什麼。

我們並不需要指定版本號,起步依賴本身的版本是由正在使用的Spring Boot的版本來決定的,而起步依賴則會決定它們引入的傳遞依賴的版本。

不知道自己所用依賴的版本,你多少會有些不安。你要有信心,相信Spring Boot經過了足夠的測試,確保引入的全部依賴都能相互兼容。這是一種解脫,只需指定起步依賴,不用擔心自己需要維護哪些庫,也不必擔心它們的版本。

但如果你真想知道自己在用什麼,在構建工具裡總能找到你要的答案。在Gradle裡,dependencies 任務會顯示一個依賴樹,其中包含了項目所用的每一個庫以及它們的版本:

$ gradle dependencies

  

在Maven裡使用dependency插件的tree目標也能獲得相似的依賴樹。

$ mvn dependency:tree

  

大部分情況下,你都無需關心每個Spring Boot起步依賴分別聲明了些什麼東西。Web起步依賴能讓你構建Web應用程序,Thymeleaf起步依賴能讓你用Thymeleaf模板,Spring Data JPA起步依賴能讓你用Spring Data JPA將數據持久化到數據庫裡,通常只要知道這些就足夠了。

但是,即使經過了Spring Boot團隊的測試,起步依賴裡所選的庫仍有問題該怎麼辦?如何覆蓋起步依賴呢?

2.2.2 覆蓋起步依賴引入的傳遞依賴

說到底,起步依賴和你項目裡的其他依賴沒什麼區別。也就是說,你可以通過構建工具中的功能,選擇性地覆蓋它們引入的傳遞依賴的版本號,排除傳遞依賴,當然還可以為那些Spring Boot起步依賴沒有涵蓋的庫指定依賴。

以Spring Boot的Web起步依賴為例,它傳遞依賴了Jackson JSON庫。如果你正在構建一個生產或消費JSON資源表述的REST服務,那它會很有用。但是,要構建傳統的面向人類用戶的Web應用程序,你可能用不上Jackson。雖然把它加進來也不會有什麼壞處,但排除掉它的傳遞依賴,可以為你的項目瘦身。

如果在用Gradle,你可以這樣排除傳遞依賴:

compile(\"org.springframework.boot:spring-boot-starter-web\") {
  exclude group: \'com.fasterxml.jackson.core\'
}

  

在Maven裡,可以用<exclusions>元素來排除傳遞依賴。下面這個引入Spring Boot的build.gradle的<dependency>增加了<exclusions>元素去除Jackson:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
  <exclusions>
    <exclusion>
      <groupId>com.fasterxml.jackson.core</groupId>
    </exclusion>
  </exclusions>
</dependency>

  

另一方面,也許項目需要Jackson,但你需要用另一個版本的Jackson來進行構建,而不是Web起步依賴裡的那個。假設Web起步依賴引用了Jackson 2.3.4,但你需要使用2.4.33。在Maven裡,你可以直接在pom.xml中表達訴求,就像這樣:

3此處提到的版本僅作演示之用,Spring Boot的Web起步依賴所引用的實際Jackson版本由你使用的Spring Boot版本決定。

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.4.3</version>
</dependency>

  

Maven總是會用最近的依賴,也就是說,你在項目的構建說明文件裡增加的這個依賴,會覆蓋傳遞依賴引入的另一個依賴。

與之類似,如果你用的是Gradle,可以在build.gradle文件裡指明你要的Jackson的版本:

compile(\"com.fasterxml.jackson.core:jackson-databind:2.4.3\")

  

因為這個依賴的版本比Spring Boot的Web起步依賴引入的要新,所以在Gradle裡是生效的。但假如你要的不是新版本的Jackson,而是一個較早的版本呢?Gradle和Maven不太一樣,Gradle傾向於使用庫的最新版本。因此,如果你要使用老版本的Jackon,則不得不把老版本的依賴加入構建,並把Web起步依賴傳遞依賴的那個版本排除掉:

compile(\"org.springframework.boot:spring-boot-starter-web\") {
  exclude group: \'com.fasterxml.jackson.core\'
}
compile(\"com.fasterxml.jackson.core:jackson-databind:2.3.1\")

  

不管什麼情況,在覆蓋Spring Boot起步依賴引入的傳遞依賴時都要多加小心。雖然不同的版本放在一起也許沒什麼問題,但你要知道,起步依賴中各個依賴版本之間的兼容性都經過了精心的測試。應該只在特殊的情況下覆蓋這些傳遞依賴(比如新版本修復了一個bug)。

現在我們有了一個空的項目結構,構建說明文件也準備好了,是時候開發應用程序了。我們會讓Spring Boot來處理配置細節,而我們自己則專注於編寫閱讀列表功能相關的代碼。