使用 Spring Boot 快速構建 Spring 框架應用

Spring 框架作爲目前非常流行的一個 Java 應用開發框架,它所包含的內容是非常繁多的。Spring 框架包含幾十個不同的子項目,涵蓋應用開發的不同方面。要在這些子項目之間進行選擇,並快速搭建一個可以運行的應用是比較困難的事情。Spring Boot 的目的在於快速創建可以獨立運行的 Spring 應用。通過 Spring Boot 可以根據相應的模板快速創建應用並運行。Spring Boot 可以自動配置 Spring 的各種組件,並不依賴代碼生成和 XML 配置文件。Spring Boot 可以大大提升使用 Spring 框架時的開發效率。


Spring 框架對於很多 Java 開發人員來說都不陌生。自從 2002 年發佈以來,Spring 框架已經成爲企業應用開發領域非常流行的基礎框架。有大量的企業應用基於 Spring 框架來開發。Spring 框架包含幾十個不同的子項目,涵蓋應用開發的不同方面。如此多的子項目和組件,一方面方便了開發人員的使用,另外一個方面也帶來了使用方面的問題。每個子項目都有一定的學習曲線。開發人員需要了解這些子項目和組件的具體細節,才能知道如何把這些子項目整合起來形成一個完整的解決方案。在如何使用這些組件上,並沒有相關的最佳實踐提供指導。對於新接觸 Spring 框架的開發人員來說,並不知道如何更好的使用這些組件。Spring 框架的另外一個常見問題是要快速創建一個可以運行的應用比較麻煩。Spring Boot 是 Spring 框架的一個新的子項目,用於創建 Spring 4.0 項目。它的開發始於 2013 年。2014 年 4 月發佈 1.0.0 版本。它可以自動配置 Spring 的各種組件,並不依賴代碼生成和 XML 配置文件。Spring Boot 也提供了對於常見場景的推薦組件配置。Spring Boot 可以大大提升使用 Spring 框架時的開發效率。本文將對 Spring Boot 進行詳細的介紹。

簡介

從 Spring Boot 項目名稱中的 Boot 可以看出來,Spring Boot 的作用在於創建和啓動新的基於 Spring 框架的項目。它的目的是幫助開發人員很容易的創建出獨立運行和產品級別的基於 Spring 框架的應用。Spring Boot 會選擇最適合的 Spring 子項目和第三方開源庫進行整合。大部分 Spring Boot 應用只需要非常少的配置就可以快速運行起來。

Spring Boot 包含的特性如下:

  • 創建可以獨立運行的 Spring 應用。
  • 直接嵌入 Tomcat 或 Jetty 服務器,不需要部署 WAR 文件。
  • 提供推薦的基礎 POM 文件來簡化 Apache Maven 配置。
  • 儘可能的根據項目依賴來自動配置 Spring 框架。
  • 提供可以直接在生產環境中使用的功能,如性能指標、應用信息和應用健康檢查。
  • 沒有代碼生成,也沒有 XML 配置文件。

通過 Spring Boot,創建新的 Spring 應用變得非常容易,而且創建出的 Spring 應用符合通用的最佳實踐。只需要簡單的幾個步驟就可以創建出一個 Web 應用。下面介紹使用 Maven 作爲構建工具創建的 Spring Boot 應用。代碼清單 1 給出了該應用的 POM 文件。

清單 1. Spring Boot 示例應用的 POM 文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.midgetontoes</groupId>
<artifactId>spring-boot-simple</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
 <spring.boot.version>1.1.4.RELEASE</spring.boot.version>
</properties>
<dependencies>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-web</artifactId>
 <version>${spring.boot.version}</version>
 </dependency>
</dependencies>
<build>
 <plugins>
 <plugin>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
 <executions>
 <execution>
 <goals>
 <goal>repackage</goal>
 </goals>
 </execution>
 </executions>
 </plugin>
 </plugins>
</build>
</project>

代碼清單 1 中的 POM 文件中可以看到,應用所聲明的依賴很少,只有一個“org.springframework.boot:spring-boot-starter-web”,而不是像其他 Spring 項目一樣需要聲明很多的依賴。當使用 Maven 命令“mvn dependency:tree”來查看項目實際的依賴時,會發現其中包含了 Spring MVC 框架、SLF4J、Jackson、Hibernate Validator 和 Tomcat 等依賴。這實際上 Spring 推薦的 Web 應用中使用的開源庫的組合。代碼清單 2 中給出了示例應用的 Java 代碼。

清單 2. Spring Boot 示例應用的 Java 代碼
@RestController
@EnableAutoConfiguration
public class Application {
 @RequestMapping("/")
 String home() {
 return "Hello World!";
 }
 public static void main(String[] args) throws Exception {
 SpringApplication.run(Application.class, args);
 }
}

代碼清單 2 中的 Java 類 Application 是一個簡單的可以獨立運行的 Web 應用。直接運行該 Java 類會啓動一個內嵌的 Tomcat 服務器運行在 8080 端口。訪問“http://localhost:8080”可以看到頁面上顯示“Hello World!”。也就是說,只需要簡單的 2 個文件就可以啓動一個獨立運行的 Web 應用。並不需要額外安裝 Tomcat 這樣的應用服務器,也不需要打包成 WAR 文件。可以通過“mvn spring-boot:run”在命令行啓動該應用。在代碼清單 1 中的 POM 文件中添加了“org.springframework.boot:spring-boot-maven-plugin”插件。在添加了該插件之後,當運行“mvn package”進行打包時,會打包成一個可以直接運行的 JAR 文件,使用“java -jar”命令就可以直接運行。這在很大程度上簡化了應用的部署,只需要安裝了 JRE 就可以運行。

代碼清單 2 中的“@EnableAutoConfiguration”註解的作用在於讓 Spring Boot 根據應用所聲明的依賴來對 Spring 框架進行自動配置,這就減少了開發人員的工作量。註解“@RestController”和”@RequestMapping”由 Spring MVC 提供,用來創建 REST 服務。這兩個註解和 Spring Boot 本身並沒有關係。

Spring Boot 推薦的基礎 POM 文件

上一節的代碼清單 1 中給出的“org.springframework.boot:spring-boot-starter-web”是 Spring Boot 所提供的推薦的基礎 POM 文件之一,用來提供創建基於 Spring MVC 的 Web 應用所需的第三方庫依賴。除了這個 POM 文件之外,Spring Boot 還提供了其他類似的 POM 文件。所有這些基礎 POM 依賴都在“org.springframework.boot”組中。一些重要 POM 文件的具體說明見表 1

表 1. Spring Boot 推薦的基礎 POM 文件
名稱 說明
spring-boot-starter 核心 POM,包含自動配置支持、日誌庫和對 YAML 配置文件的支持。
spring-boot-starter-amqp 通過 spring-rabbit 支持 AMQP。
spring-boot-starter-aop 包含 spring-aop 和 AspectJ 來支持面向切面編程(AOP)。
spring-boot-starter-batch 支持 Spring Batch,包含 HSQLDB。
spring-boot-starter-data-jpa 包含 spring-data-jpa、spring-orm 和 Hibernate 來支持 JPA。
spring-boot-starter-data-mongodb 包含 spring-data-mongodb 來支持 MongoDB。
spring-boot-starter-data-rest 通過 spring-data-rest-webmvc 支持以 REST 方式暴露 Spring Data 倉庫。
spring-boot-starter-jdbc 支持使用 JDBC 訪問數據庫。
spring-boot-starter-security 包含 spring-security。
spring-boot-starter-test 包含常用的測試所需的依賴,如 JUnit、Hamcrest、Mockito 和 spring-test 等。
spring-boot-starter-velocity 支持使用 Velocity 作爲模板引擎。
spring-boot-starter-web 支持 Web 應用開發,包含 Tomcat 和 spring-mvc。
spring-boot-starter-websocket 支持使用 Tomcat 開發 WebSocket 應用。
spring-boot-starter-ws 支持 Spring Web Services。
spring-boot-starter-actuator 添加適用於生產環境的功能,如性能指標和監測等功能。
spring-boot-starter-remote-shell 添加遠程 SSH 支持。
spring-boot-starter-jetty 使用 Jetty 而不是默認的 Tomcat 作爲應用服務器。
spring-boot-starter-log4j 添加 Log4j 的支持。
spring-boot-starter-logging 使用 Spring Boot 默認的日誌框架 Logback。
spring-boot-starter-tomcat 使用 Spring Boot 默認的 Tomcat 作爲應用服務器。

所有這些 POM 依賴的好處在於爲開發 Spring 應用提供了一個良好的基礎。Spring Boot 所選擇的第三方庫是經過考慮的,是比較適合產品開發的選擇。但是 Spring Boot 也提供了不同的選項,比如日誌框架可以用 Logback 或 Log4j,應用服務器可以用 Tomcat 或 Jetty。

自動配置

Spring Boot 對於開發人員最大的好處在於可以對 Spring 應用進行自動配置。Spring Boot 會根據應用中聲明的第三方依賴來自動配置 Spring 框架,而不需要進行顯式的聲明。比如當聲明瞭對 HSQLDB 的依賴時,Spring Boot 會自動配置成使用 HSQLDB 進行數據庫操作。

Spring Boot 推薦採用基於 Java 註解的配置方式,而不是傳統的 XML。只需要在主配置 Java 類上添加“@EnableAutoConfiguration”註解就可以啓用自動配置。Spring Boot 的自動配置功能是沒有侵入性的,只是作爲一種基本的默認實現。開發人員可以通過定義其他 bean 來替代自動配置所提供的功能。比如當應用中定義了自己的數據源 bean 時,自動配置所提供的 HSQLDB 就不會生效。這給予了開發人員很大的靈活性。既可以快速的創建一個可以立即運行的原型應用,又可以不斷的修改和調整以適應應用開發在不同階段的需要。可能在應用最開始的時候,嵌入式的內存數據庫(如 HSQLDB)就足夠了,在後期則需要換成 MySQL 等數據庫。Spring Boot 使得這樣的切換變得很簡單。

外部化的配置

在應用中管理配置並不是一個容易的任務,尤其是在應用需要部署到多個環境中時。通常會需要爲每個環境提供一個對應的屬性文件,用來配置各自的數據庫連接信息、服務器信息和第三方服務賬號等。通常的應用部署會包含開發、測試和生產等若干個環境。不同的環境之間的配置存在覆蓋關係。測試環境中的配置會覆蓋開發環境,而生產環境中的配置會覆蓋測試環境。Spring 框架本身提供了多種的方式來管理配置屬性文件。Spring 3.1 之前可以使用 PropertyPlaceholderConfigurer。Spring 3.1 引入了新的環境(Environment)和概要信息(Profile)API,是一種更加靈活的處理不同環境和配置文件的方式。不過 Spring 這些配置管理方式的問題在於選擇太多,讓開發人員無所適從。Spring Boot 提供了一種統一的方式來管理應用的配置,允許開發人員使用屬性文件、YAML 文件、環境變量和命令行參數來定義優先級不同的配置值。

Spring Boot 所提供的配置優先級順序比較複雜。按照優先級從高到低的順序,具體的列表如下所示。

  1. 命令行參數。
  2. 通過 System.getProperties() 獲取的 Java 系統參數。
  3. 操作系統環境變量。
  4. 從 java:comp/env 得到的 JNDI 屬性。
  5. 通過 RandomValuePropertySource 生成的“random.*”屬性。
  6. 應用 Jar 文件之外的屬性文件。
  7. 應用 Jar 文件內部的屬性文件。
  8. 在應用配置 Java 類(包含“@Configuration”註解的 Java 類)中通過“@PropertySource”註解聲明的屬性文件。
  9. 通過“SpringApplication.setDefaultProperties”聲明的默認屬性。

Spring Boot 的這個配置優先級看似複雜,其實是很合理的。比如命令行參數的優先級被設置爲最高。這樣的好處是可以在測試或生產環境中快速地修改配置參數值,而不需要重新打包和部署應用。

SpringApplication 類默認會把以“--”開頭的命令行參數轉化成應用中可以使用的配置參數,如 “--name=Alex” 會設置配置參數 “name” 的值爲 “Alex”。如果不需要這個功能,可以通過 “SpringApplication.setAddCommandLineProperties(false)” 禁用解析命令行參數。

RandomValuePropertySource 可以用來生成測試所需要的各種不同類型的隨機值,從而免去了在代碼中生成的麻煩。RandomValuePropertySource 可以生成數字和字符串。數字的類型包含 int 和 long,可以限定數字的大小範圍。以“random.”作爲前綴的配置屬性名稱由 RandomValuePropertySource 來生成,如代碼清單 3 所示。

清單 3. 使用 RandomValuePropertySource 生成的配置屬性
user.id=${random.value}
user.count=${random.int}
user.max=${random.long}
user.number=${random.int(100)}
user.range=${random.int[100, 1000]}

屬性文件

屬性文件是最常見的管理配置屬性的方式。Spring Boot 提供的 SpringApplication 類會搜索並加載 application.properties 文件來獲取配置屬性值。SpringApplication 類會在下面位置搜索該文件。

  • 當前目錄的“/config”子目錄。
  • 當前目錄。
  • classpath 中的“/config”包。
  • classpath

上面的順序也表示了該位置上包含的屬性文件的優先級。優先級按照從高到低的順序排列。可以通過“spring.config.name”配置屬性來指定不同的屬性文件名稱。也可以通過“spring.config.location”來添加額外的屬性文件的搜索路徑。如果應用中包含多個 profile,可以爲每個 profile 定義各自的屬性文件,按照“application-{profile}”來命名。

對於配置屬性,可以在代碼中通過“@Value”來使用,如代碼清單 4 所示。

清單 4. 通過“@Value”來使用配置屬性
@RestController
@EnableAutoConfiguration
public class Application {
 @Value("${name}")
 private String name;
 @RequestMapping("/")
 String home() {
 return String.format("Hello %s!", name);
 }
}

代碼清單 4 中,變量 name 的值來自配置屬性中的“name”屬性。

YAML

相對於屬性文件來說,YAML 是一個更好的配置文件格式。YAML 在 Ruby on Rails 中得到了很好的應用。SpringApplication 類也提供了對 YAML 配置文件的支持,只需要添加對 SnakeYAML 的依賴即可。代碼清單 5 給出了 application.yml 文件的示例。

清單 5. 使用 YAML 表示的配置屬性
spring:
 profiles: development
db:
 url: jdbc:hsqldb:file:testdb
 username: sa
 password:
---
spring:
 profiles: test
db:
 url: jdbc:mysql://localhost/test
 username: test
 password: test

代碼清單 5 中的 YAML 文件同時給出了 development 和 test 兩個不同的 profile 的配置信息,這也是 YAML 文件相對於屬性文件的優勢之一。除了使用“@Value”註解綁定配置屬性值之外,還可以使用更加靈活的方式。代碼清單 6 給出的是使用代碼清單 5 中的 YAML 文件的 Java 類。通過“@ConfigurationProperties(prefix="db")”註解,配置屬性中以“db”爲前綴的屬性值會被自動綁定到 Java 類中同名的域上,如 url 域的值會對應屬性“db.url”的值。只需要在應用的配置類中添加“@EnableConfigurationProperties”註解就可以啓用該自動綁定功能。

清單 6. 使用 YAML 文件的 Java 類
@Component
@ConfigurationProperties(prefix="db")
public class DBSettings {
 private String url;
 private String username;
 private String password;
}

開發 Web 應用

Spring Boot 非常適合於開發基於 Spring MVC 的 Web 應用。通過內嵌的 Tomcat 或 Jetty 服務器,可以簡化對 Web 應用的部署。Spring Boot 通過自動配置功能對 Spring MVC 應用做了一些基本的配置,使其更加適合一般 Web 應用的開發要求。

HttpMessageConverter

Spring MVC 中使用 HttpMessageConverter 接口來在 HTTP 請求和響應之間進行消息格式的轉換。默認情況下已經通過 Jackson 支持 JSON 和通過 JAXB 支持 XML 格式。可以通過創建自定義 HttpMessageConverters 的方式來添加其他的消息格式轉換實現。

靜態文件

默認情況下,Spring Boot 可以對 “/static”、“/public”、“/resources” 或 “/META-INF/resources” 目錄下的靜態文件提供支持。同時 Spring Boot 還支持 Webjars。路徑“/webjars/**”下的內容會由 webjar 格式的 Jar 包來提供。

生產環境運維支持

與開發和測試環境不同的是,當應用部署到生產環境時,需要各種運維相關的功能的支持,包括性能指標、運行信息和應用管理等。所有這些功能都有很多技術和開源庫可以實現。Spring Boot 對這些運維相關的功能進行了整合,形成了一個功能完備和可定製的功能集,稱之爲 Actuator。只需要在 POM 文件中增加對 “org.springframe.boot:spring-boot-starter-actuator” 的依賴就可以添加 Actuator。Actuator 在添加之後,會自動暴露一些 HTTP 服務來提供這些信息。這些 HTTP 服務的說明如表 2

表 2. Spring Boot Actuator 所提供的 HTTP 服務
名稱 說明 是否包含敏感信息
autoconfig 顯示 Spring Boot 自動配置的信息。
beans 顯示應用中包含的 Spring bean 的信息。
configprops 顯示應用中的配置參數的實際值。
dump 生成一個 thread dump。
env 顯示從 ConfigurableEnvironment 得到的環境配置信息。
health 顯示應用的健康狀態信息。
info 顯示應用的基本信息。
metrics 顯示應用的性能指標。
mappings 顯示 Spring MVC 應用中通過“
@RequestMapping”添加的路徑映射。
shutdown 關閉應用。
trace 顯示應用相關的跟蹤(trace)信息。

對於表 2中的每個服務,通過訪問名稱對應的 URL 就可以獲取到相關的信息。如訪問“/info”就可以獲取到 info 服務對應的信息。服務是否包含敏感信息說明了該服務暴露出來的信息是否包含一些比較敏感的信息,從而確定是否需要添加相應的訪問控制,而不是對所有人都公開。所有的這些服務都是可以配置的,比如通過改變名稱來改變相應的 URL。下面對幾個重要的服務進行介紹。

health 服務

Spring Boot 默認提供了對應用本身、關係數據庫連接、MongoDB、Redis 和 Rabbit MQ 的健康狀態的檢測功能。當應用中添加了 DataSource 類型的 bean 時,Spring Boot 會自動在 health 服務中暴露數據庫連接的信息。應用也可以提供自己的健康狀態信息,如代碼清單 7 所示。

清單 7. 自定義 health 服務
@Component
public class AppHealthIndicator implements HealthIndicator {
 @Override
 public Health health() {
 return Health.up().build();
 }
}

應用只需要實現 org.springframework.boot.actuate.health.HealthIndicator 接口,並返回一個 org.springframework.boot.actuate.health.Health 對象,就可以通過 health 服務來獲取所暴露的信息。如代碼清單 8 所示。

清單 8. health 服務返回的結果
{"status":"UP","app":{"status":"UP"},"db":{"status":"UP","database":"HSQL Database Engine","hello":1}}

info 服務

info 服務所暴露的信息是完全由應用來確定的。應用中任何以“info.”開頭的配置參數會被自動的由 info 服務來暴露。只需要往 application.properties 中添加以“info.”開頭的參數即可,如代碼清單 9 所示。

清單 9. 添加 info 服務所需配置參數的屬性文件
info.app_name=My First Spring Boot Application
info.app_version=1.0.0

當訪問“/info”時,訪問的 JSON 數據如代碼清單 10 所示。

清單 10. Info 服務返回的結果
{"app_name":"My First Spring Boot Application","app_version":"1.0.0"}

metrics 服務

當訪問 metrics 服務時,可以看到 Spring Boot 通過 SystemPublicMetrics 默認提供的一些系統的性能參數值,包括內存、CPU、Java 類加載和線程等的基本信息。應用可以記錄其他所需要的信息。Spring Boot 默認提供了兩種類型的性能指標記錄方式:gauge 和 counter。gauge 用來記錄單個絕對數值,counter 用來記錄增量或減量值。比如在一個 Web 應用中,可以用 counter 來記錄當前在線的用戶數量。當用戶登錄時,把 counter 的值加 1;當用戶退出時,把 counter 的值減 1。代碼清單 11 給出了一個示例。

清單 11. 自定義的 metrics 服務
@RestController
public class GreetingsController {
 @Autowired
 private CounterService counterService;
 @RequestMapping("/greet")
 public String greet() {
 counterService.increment("myapp.greet.count");
 return "Hello!";
 }
}

代碼清單 11 中添加了對 Spring Boot 提供的 CounterService 的依賴。當 greet 方法被調用時,會把名稱爲“myapp.greet.count”的計數器的值加 1。也就是當用戶每次訪問“/greet”時,該計算器就會被加 1。除了 CounterService 之外,還可以使用 GaugeService 來記錄絕對值。

使用 JMX 進行管理

添加 Actuator 後所暴露的 HTTP 服務只能提供只讀的信息。如果需要對應用在運行時進行管理,則需要用到 JMX。Spring Boot 默認提供了 JMX 管理的支持。只需要通過 JDK 自帶的 JConsole 連接到應用的 JMX 服務器,就可以看到在域“org.springframework.boot”中 mbean。可以通過 Spring 提供的 @ManagedResource、@ManagedAttribute 和 @ManagedOperation 註解來創建應用自己的 mbean。

使用 Spring Boot CLI

Spring Boot 提供了命令行工具來運行 Groovy 文件。命令行工具的安裝非常簡單,只需要下載之後解壓縮即可。下載地址見參考資源。解壓之後可以運行 spring 命令來使用該工具。通過 Groovy 開發的應用與使用 Java 並沒有差別,只不過使用 Groovy 簡化的語法可以使得代碼更加簡單。代碼清單 12 給出了與代碼清單 2 功能相同的 Groovy 實現。

清單 12. 使用 Groovy 的示例應用
@RestController
class WebApplication {
 @RequestMapping("/")
 String home() {
 "Hello World!"
 }
}

只需要使用“spring run app.groovy”就可以運行該應用。還可以使用 Groovy 提供的 DSL 支持來簡化應用,如代碼清單 13 所示。

清單 13. 使用 Groovy DSL 簡化應用
@RestController
class WebApplication {
 @Autowired
 Service service
 @RequestMapping("/")
 String home() {
 service.greet()
 }
}
class Service {
String message
 String greet() {
 message
 }
}
beans {
 service(Service) {
 message = "Another Hello"
 }
}

代碼清單 13 中,通過“beans”DSL 可以快速創建和配置 Spring bean。

結束語

對於廣大使用 Spring 框架的開發人員來說,Spring Boot 無疑是一個非常實用的工具。本文詳細介紹瞭如何通過 Spring Boot 快速創建 Spring 應用以及它所提供的自動配置和外部化配置的能力,同時還介紹了 Spring Boot 內建的 Actuator 提供的可以在生產環境中直接使用的性能指標、運行信息和應用管理等功能,最後介紹了 Spring Boot 命令行工具的使用。通過基於依賴的自動配置功能,使得 Spring 應用的配置變得非常簡單。在依賴的管理上也變得更加簡單,不需要開發人員自己來進行整合。Actuator 所提供的功能非常實用,對於在生產環境下對應用的監控和管理是大有好處的。Spring Boot 應該成爲每個使用 Spring 框架的開發人員使用的工具。

參考資料

學習

發佈了98 篇原創文章 · 獲贊 87 · 訪問量 67萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章