讀古今文學網 > Spring Boot實戰 > 1.1 Spring風雲再起 >

1.1 Spring風雲再起

Spring誕生時是Java企業版(Java Enterprise Edition,JEE,也稱J2EE)的輕量級代替品。無需開發重量級的Enterprise JavaBean(EJB),Spring為企業級Java開發提供了一種相對簡單的方法,通過依賴注入和面向切面編程,用簡單的Java對像(Plain Old Java Object,POJO)實現了EJB的功能。

雖然Spring的組件代碼是輕量級的,但它的配置卻是重量級的。一開始,Spring用XML配置,而且是很多XML配置。Spring 2.5引入了基於註解的組件掃瞄,這消除了大量針對應用程序自身組件的顯式XML配置。Spring 3.0引入了基於Java的配置,這是一種類型安全的可重構配置方式,可以代替XML。

儘管如此,我們依舊沒能逃脫配置的魔爪。開啟某些Spring特性時,比如事務管理和Spring MVC,還是需要用XML或Java進行顯式配置。啟用第三方庫時也需要顯式配置,比如基於Thymeleaf的Web視圖。配置Servlet和過濾器(比如Spring的DispatcherServlet)同樣需要在web.xml或Servlet初始化代碼裡進行顯式配置。組件掃瞄減少了配置量,Java配置讓它看上去簡潔不少,但Spring還是需要不少配置。

所有這些配置都代表了開發時的損耗。因為在思考Spring特性配置和解決業務問題之間需要進行思維切換,所以寫配置擠佔了寫應用程序邏輯的時間。和所有框架一樣,Spring實用,但與此同時它要求的回報也不少。

除此之外,項目的依賴管理也是件吃力不討好的事情。決定項目裡要用哪些庫就已經夠讓人頭痛的了,你還要知道這些庫的哪個版本和其他庫不會有衝突,這難題實在太棘手。

並且,依賴管理也是一種損耗,添加依賴不是寫應用程序代碼。一旦選錯了依賴的版本,隨之而來的不兼容問題毫無疑問會是生產力殺手。

Spring Boot讓這一切成為了過去。

1.1.1 重新認識Spring

假設你受命用Spring開發一個簡單的Hello World Web應用程序。你該做什麼?我能想到一些基本的需要。

  • 一個項目結構,其中有一個包含必要依賴的Maven或者Gradle構建文件,最起碼要有Spring MVC和Servlet API這些依賴。

  • 一個web.xml文件(或者一個WebApplicationInitializer實現),其中聲明了Spring的DispatcherServlet

  • 一個啟用了Spring MVC的Spring配置。

  • 一個控制器類,以「Hello World」響應HTTP請求。

  • 一個用於部署應用程序的Web應用服務器,比如Tomcat。

最讓人難以接受的是,這份清單裡只有一個東西是和Hello World功能相關的,即控制器,剩下的都是Spring開發的Web應用程序必需的通用樣板。既然所有Spring Web應用程序都要用到它們,那為什麼還要你來提供這些東西呢?

假設這裡只需要控制器。代碼清單1-1所示基於Groovy的控制器類就是一個簡單而完整的Spring應用程序。

代碼清單1-1 一個完整的基於Groovy的Spring應用程序

@RestController
class HelloController {

  @RequestMapping(\"/\")
  def hello {
    return \"Hello World\"
  }

}

  

這裡沒有配置,沒有web.xml,沒有構建說明,甚至沒有應用服務器,但這就是整個應用程序了。Spring Boot會搞定執行應用程序所需的各種後勤工作,你只要搞定應用程序的代碼就好。

假設你已經裝好了Spring Boot的命令行界面(Command Line Interface,CLI),可以像下面這樣在命令行裡運行HelloController

$ spring run HelloController.groovy

  

想必你已經注意到了,這裡甚至沒有編譯代碼,Spring Boot CLI可以運行未經編譯的代碼。

之所以選擇用Groovy來寫這個控制器示例,是因為Groovy語言的簡潔與Spring Boot的簡潔有異曲同工之妙。但Spring Boot並不強制要求使用Groovy。實際上,本書中的很多代碼都是用Java寫的,但在恰當的時候,偶爾也會出現一些Groovy代碼。

不要客氣,直接跳到1.2.1節吧,看看如何安裝Spring Boot CLI,這樣你就能試著編寫這個小小的Web應用程序了。現在,你將看到Spring Boot的關鍵部分,看到它是如何改變Spring應用程序的開發方式的。

1.1.2 Spring Boot精要

Spring Boot將很多魔法帶入了Spring應用程序的開發之中,其中最重要的是以下四個核心。

  • 自動配置:針對很多Spring應用程序常見的應用功能,Spring Boot能自動提供相關配置。

  • 起步依賴:告訴Spring Boot需要什麼功能,它就能引入需要的庫。

  • 命令行界面:這是Spring Boot的可選特性,借此你只需寫代碼就能完成完整的應用程序,無需傳統項目構建。

  • Actuator:讓你能夠深入運行中的Spring Boot應用程序,一探究竟。

每一個特性都在通過自己的方式簡化Spring應用程序的開發。本書會探尋如何將它們發揮到極致,但就目前而言,先簡單看看它們都提供了哪些功能吧。

1. 自動配置

在任何Spring應用程序的源代碼裡,你都會找到Java配置或XML配置(抑或兩者皆有),它們為應用程序開啟了特定的特性和功能。舉個例子,如果你寫過用JDBC訪問關係型數據庫的應用程序,那你一定在Spring應用程序上下文裡配置過JdbcTemplate這個Bean。我打賭那段配置看起來是這樣的:

@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
  return new JdbcTemplate(dataSource);
}

  

這段非常簡單的Bean聲明創建了一個JdbcTemplate的實例,注入了一個DataSource依賴。當然,這意味著你還需要配置一個DataSource的Bean,這樣才能滿足依賴。假設你將配置一個嵌入式H2數據庫作為DataSource Bean,完成這個配置場景的代碼大概是這樣的:

@Bean
public DataSource dataSource {
  return new EmbeddedDatabaseBuilder
          .setType(EmbeddedDatabaseType.H2)
          .addScripts(\'schema.sql\', \'data.sql\')
          .build;
}

  

這個Bean配置方法創建了一個嵌入式數據庫,並指定在該數據庫上執行兩段SQL腳本。build方法返回了一個指向該數據庫的引用。

這兩個Bean配置方法都不複雜,也不是很長,但它們只是典型Spring應用程序配置的一小部分。除此之外,還有無數Spring應用程序有著完全相同的方法。所有需要用到嵌入式數據庫和JdbcTemplate的應用程序都會用到那些方法。簡而言之,這就是一個樣板配置。

既然它如此常見,那為什麼還要你去寫呢?

Spring Boot會為這些常見配置場景進行自動配置。如果Spring Boot在應用程序的Classpath裡發現H2數據庫的庫,那麼它就自動配置一個嵌入式H2數據庫。如果在Classpath裡發現JdbcTemplate,那麼它還會為你配置一個JdbcTemplate的Bean。你無需操心那些Bean的配置,Spring Boot會做好準備,隨時都能將其注入到你的Bean裡。

Spring Boot的自動配置遠不止嵌入式數據庫和JdbcTemplate,它有大把的辦法幫你減輕配置負擔,這些自動配置涉及Java持久化API(Java Persistence API,JPA)、Thymeleaf模板、安全和Spring MVC。第2章會深入討論自動配置這個話題。

2. 起步依賴

向項目中添加依賴是件富有挑戰的事。你需要什麼庫?它的Group和Artifact是什麼?你需要哪個版本?哪個版本不會和項目中的其他依賴發生衝突?

Spring Boot通過起步依賴為項目的依賴管理提供幫助。起步依賴其實就是特殊的Maven依賴和Gradle依賴,利用了傳遞依賴解析,把常用庫聚合在一起,組成了幾個為特定功能而定制的依賴。

舉個例子,假設你正在用Spring MVC構造一個REST API,並將JSON(JavaScript Object Notation)作為資源表述。此外,你還想運用遵循JSR-303規範的聲明式校驗,並使用嵌入式的Tomcat服務器來提供服務。要實現以上目標,你在Maven或Gradle裡至少需要以下8個依賴:

  • org.springframework:spring-core

  • org.springframework:spring-web

  • org.springframework:spring-webmvc

  • com.fasterxml.jackson.core:jackson-databind

  • org.hibernate:hibernate-validator

  • org.apache.tomcat.embed:tomcat-embed-core

  • org.apache.tomcat.embed:tomcat-embed-el

  • org.apache.tomcat.embed:tomcat-embed-logging-juli

不過,如果打算利用Spring Boot的起步依賴,你只需添加Spring Boot的Web起步依賴(org.springframework.boot:spring-boot-starter-web)1,僅此一個。它會根據依賴傳遞把其他所需依賴引入項目裡,你都不用考慮它們。

1Spring Boot起步依賴基本都以spring-boot-starter打頭,隨後是直接代表其功能的名字,比如webtest,下文出現起步依賴的名字時,可能就直接用其前綴後的單詞來表示了。——譯者注

比起減少依賴數量,起步依賴還引入了一些微妙的變化。向項目中添加了Web起步依賴,實際上指定了應用程序所需的一類功能。因為應用是個Web應用程序,所以加入了Web起步依賴。與之類似,如果應用程序要用到JPA持久化,那麼就可以加入jpa起步依賴。如果需要安全功能,那就加入security起步依賴。簡而言之,你不再需要考慮支持某種功能要用什麼庫了,引入相關起步依賴就行。

此外,Spring Boot的起步依賴還把你從「需要這些庫的哪些版本」這個問題裡解放了出來。起步依賴引入的庫的版本都是經過測試的,因此你可以完全放心,它們之間不會出現不兼容的情況。

和自動配置一樣,第2章就會深入討論起步依賴。

3. 命令行界面

除了自動配置和起步依賴,Spring Boot還提供了一種很有意思的新方法,可以快速開發Spring應用程序。正如之前在1.1節裡看到的那樣,Spring Boot CLI讓只寫代碼即可實現應用程序成為可能。

Spring Boot CLI利用了起步依賴和自動配置,讓你專注於代碼本身。不僅如此,你是否注意到代碼清單1-1里沒有import?CLI如何知道RequestMappingRestController來自哪個包呢?說到這個問題,那些類最終又是怎麼跑到Classpath裡的呢?

說得簡單一點,CLI能檢測到你使用了哪些類,它知道要向Classpath中添加哪些起步依賴才能讓它運轉起來。一旦那些依賴出現在Classpath中,一系列自動配置就會接踵而來,確保啟用DispatcherServlet和Spring MVC,這樣控制器就能響應HTTP請求了。

Spring Boot CLI是Spring Boot的非必要組成部分。雖然它為Spring帶來了驚人的力量,大大簡化了開發,但也引入了一套不太常規的開發模型。要是這種開發模型與你的口味相去甚遠,那也沒關係,拋開CLI,你還是可以利用Spring Boot提供的其他東西。不過如果喜歡CLI,你一定想看看第5章,其中深入探討了Spring Boot CLI。

4. Actuator

Spring Boot的最後一塊「拼圖」是Actuator,其他幾個部分旨在簡化Spring開發,而Actuator則要提供在運行時檢視應用程序內部情況的能力。安裝了Actuator就能窺探應用程序的內部情況了,包括如下細節:

  • Spring應用程序上下文裡配置的Bean

  • Spring Boot的自動配置做的決策

  • 應用程序取到的環境變量、系統屬性、配置屬性和命令行參數

  • 應用程序裡線程的當前狀態

  • 應用程序最近處理過的HTTP請求的追蹤情況

  • 各種和內存用量、垃圾回收、Web請求以及數據源用量相關的指標

Actuator通過Web端點和shell界面向外界提供信息。如果要借助shell界面,你可以打開SSH(Secure Shell),登入運行中的應用程序,發送指令查看它的情況。

第7章會詳細探索Actuator的功能。

1.1.3 Spring Boot不是什麼

因為Spring Boot實在是太驚艷了,所以過去一年多的時間裡有不少和它相關的言論。原先聽到或看到的東西可能給你造成了一些誤解,繼續學習本書前應該先澄清這些誤會。

首先,Spring Boot不是應用服務器。這個誤解是這樣產生的:Spring Boot可以把Web應用程序變為可自執行的JAR文件,不用部署到傳統Java應用服務器裡就能在命令行裡運行。Spring Boot在應用程序裡嵌入了一個Servlet容器(Tomcat、Jetty或Undertow),以此實現這一功能。但這是內嵌的Servlet容器提供的功能,不是Spring Boot實現的。

與之類似,Spring Boot也沒有實現諸如JPA或JMS(Java Message Service,Java消息服務)之類的企業級Java規範。它的確支持不少企業級Java規範,但是要在Spring裡自動配置支持那些特性的Bean。例如,Spring Boot沒有實現JPA,不過它自動配置了某個JPA實現(比如Hibernate)的Bean,以此支持JPA。

最後,Spring Boot沒有引入任何形式的代碼生成,而是利用了Spring 4的條件化配置特性,以及Maven和Gradle提供的傳遞依賴解析,以此實現Spring應用程序上下文裡的自動配置。

簡而言之,從本質上來說,Spring Boot就是Spring,它做了那些沒有它你自己也會去做的Spring Bean配置。謝天謝地,幸好有Spring,你不用再寫這些樣板配置了,可以專注於應用程序的邏輯,這些才是應用程序獨一無二的東西。

現在,你應該對Spring Boot有了大概的認識,是時候構建你的第一個Spring Boot應用程序了。先從重要的事情開始,該怎麼入手呢?