標籤:thread exec 工具 world back 協助 throws enable 最佳實務
從SpringBoot項目名稱中的 Boot 可以看出來,SpringBoot的作用在於建立和啟動新的基於Spring架構的項目。它的目的是協助開發人員很容易的建立出獨立運行和產品層級的基於 Spring架構的應用。SpringBoot會選擇最適合的Spring子項目和第三方開源庫進行整合。大部分SpringBoot應用只需要非常少的 配置就可以快速運行起來。SpringBoot包含的特性如下:建立可以獨立啟動並執行Spring應用。直接嵌入 Tomcat 或 Jetty 伺服器,不需要部署 WAR 檔案。提供推薦的基礎 POM 檔案來簡化 Apache Maven 配置。儘可能的根據項目依賴來自動設定Spring架構。提供可以直接在生產環境中使用的功能,如效能指標、應用資訊和應用健全狀態檢查。沒有代碼產生,也沒有 XML 設定檔。通過 SpringBoot,建立新的Spring應用變得非常容易,而且建立出的Spring應用符合通用的最佳實務。只需要簡單的幾個步驟就可以建立出一個 Web 應用程式。下面介紹使用 Maven 作為構建工具建立的SpringBoot應用。代碼執行個體1 給出了該應用的 POM 檔案。
執行個體1.SpringBoot樣本應用的 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”來查看項目實際的依賴時,會發現其中包含了SpringMVC 架構、SLF4J、Jackson、Hibernate Validator 和 Tomcat 等依賴。這實際上Spring推薦的 Web 應用程式中使用的開源庫的組合。代碼執行個體2 中給出了樣本應用的 Java 代碼。
執行個體2.SpringBoot樣本應用的 Java 代碼@RestController@EnableAutoConfigurationpublic 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”註解的作用在於讓SpringBoot根據應用所聲明的依賴來對Spring架構進行自動配 置,這就減少了開發人員的工作量。註解“@RestController”和”@RequestMapping”由SpringMVC 提供,用來建立 REST 服務。這兩個註解和SpringBoot本身並沒有關係。
SpringBoot推薦的基礎 POM 檔案上一節的代碼執行個體1 中給出的“org.springframework.boot:spring-boot-starter-web”是SpringBoot所提供的推薦的 基礎 POM 檔案之一,用來提供建立基於SpringMVC 的 Web 應用程式所需的第三方庫依賴。除了這個 POM 檔案之外,SpringBoot還提供了其他類似的 POM 檔案。所有這些基礎 POM 依賴都在“org.springframework.boot”組中。一些重要 POM 檔案的具體說明見表 1。SpringBoot推薦的基礎 POM 檔案1.spring-boot-starter 核心 POM,包含自動設定支援、日誌庫和對 YAML 設定檔的支援。2.spring-boot-starter-amqp 通過 spring-rabbit 支援 AMQP。3.spring-boot-starter-aop 包含 spring-aop 和 AspectJ 來支援面向切面編程(AOP)。4.spring-boot-starter-batch 支援SpringBatch,包含 HSQLDB。5.spring-boot-starter-data-jpa 包含 spring-data-jpa、spring-orm 和 Hibernate 來支援 JPA。6.spring-boot-starter-data-mongodb 包含 spring-data-mongodb 來支援 MongoDB。7.spring-boot-starter-data-rest 通過 spring-data-rest-webmvc 支援以 REST 方式暴露SpringData 倉庫。8.spring-boot-starter-jdbc 支援使用 JDBC 訪問資料庫。9.spring-boot-starter-security 包含 spring-security。10.spring-boot-starter-test 包含常用的測試所需的依賴,如 JUnit、Hamcrest、Mockito 和 spring-test 等。11.spring-boot-starter-velocity 支援使用 Velocity 作為模板引擎。12.spring-boot-starter-web 支援 Web 應用程式開發,包含 Tomcat 和 spring-mvc。13.spring-boot-starter-websocket 支援使用 Tomcat 開發 WebSocket 應用。14.spring-boot-starter-ws 支援SpringWeb Services。15.spring-boot-starter-actuator 添加適用於生產環境的功能,如效能指標和監測等功能。16.spring-boot-starter-remote-shell 添加遠程 SSH 支援。17.spring-boot-starter-jetty 使用 Jetty 而不是預設的 Tomcat 作為應用伺服器。18.spring-boot-starter-log4j 添加 Log4j 的支援。19.spring-boot-starter-logging 使用SpringBoot預設的日誌架構 Logback。20.spring-boot-starter-tomcat 使用SpringBoot預設的 Tomcat 作為應用伺服器。所有這些 POM 依賴的好處在於為開發Spring應用提供了一個良好的基礎。SpringBoot所選擇的第三方庫是經過考慮的,是比較適合產品開發的選擇。但是 SpringBoot也提供了不同的選項,比如日誌架構可以用 Logback 或 Log4j,應用伺服器可以用 Tomcat 或 Jetty。
自動設定SpringBoot對於開發人員最大的好處在於可以對Spring應用進行自動設定。SpringBoot會根據應用中聲明的第三方依賴來自動設定 Spring架構,而不需要進行顯式的聲明。比如當聲明了對 HSQLDB 的依賴時,SpringBoot會自動設定成使用 HSQLDB 進行資料庫操作。SpringBoot推薦採用基於 Java 註解的配置方式,而不是傳統的 XML。只需要在主配置 Java 類上添加“@EnableAutoConfiguration”註解就可以啟用自動設定。SpringBoot的自動設定功能是沒有侵入性的,只是作為一 種基本的預設實現。開發人員可以通過定義其他 bean 來替代自動設定所提供的功能。比如當應用中定義了自己的資料來源 bean 時,自動設定所提供的 HSQLDB 就不會生效。這給予了開發人員很大的靈活性。既可以快速的建立一個可以立即啟動並執行原型應用,又可以不斷的修改和調整以適應應用開發在不同階段的需要。可能 在應用最開始的時候,嵌入式的記憶體資料庫(如 HSQLDB)就足夠了,在後期則需要換成 MySQL 等資料庫。SpringBoot使得這樣的切換變得很簡單。
外部化的配置在應用中管理配置並不是一個容易的任務,尤其是在應用需要部署到多個環境中時。通常會需要為每個環境提供一個對應的屬性檔案,用來配置各自的資料庫連接信 息、伺服器資訊和第三方服務帳號等。通常的應用部署會包含開發、測試和生產等若干個環境。不同的環境之間的配置存在覆蓋關係。測試環境中的配置會覆蓋開發 環境,而生產環境中的配置會覆蓋測試環境。Spring 架構本身提供了多種的方式來管理配置屬性檔案。Spring 3.1 之前可以使用 PropertyPlaceholderConfigurer。Spring 3.1 引入了新的環境(Environment)和概要資訊(Profile)API,是一種更加靈活的處理不同環境和設定檔的方式。不過Spring這些配 置管理方式的問題在於選擇太多,讓開發人員無所適從。SpringBoot提供了一種統一的方式來管理應用的配置,允許開發人員使用屬性檔案、YAML 檔案、環境變數和命令列參數來定義優先順序不同的配置值。SpringBoot所提供的配置優先順序順序比較複雜。按照優先順序從高到低的順序,具體的列表如下所示。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”聲明的預設屬性。SpringBoot的這個配置優先順序看似複雜,其實是很合理的。比如命令列參數的優先順序被設定為最高。這樣的好處是可以在測試或生產環境中快速地修改配置參數值,而不需要重新打包和部署應用。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]}
屬性檔案屬性檔案是最常見的管理配置屬性的方式。SpringBoot提供的 SpringApplication 類會搜尋並載入 application.properties 檔案來擷取配置屬性值。SpringApplication 類會在下面位置搜尋該檔案。目前的目錄的“/config”子目錄。目前的目錄。classpath 中的“/config”包。classpath上面的順序也表示了該位置上包含的屬性檔案的優先順序。優先順序按照從高到低的順序排列。可以通過“spring.config.name”配置屬性來指定不 同的屬性檔案名稱。也可以通過“spring.config.location”來添加額外的屬性檔案的搜尋路徑。如果應用中包含多個 profile,可以為每個 profile 定義各自的屬性檔案,按照“application-{profile}”來命名。對於配置屬性,可以在代碼中通過“@Value”來使用,如代碼執行個體4 所示。
執行個體4. 通過“@Value”來使用配置屬性@RestController@EnableAutoConfigurationpublic 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: developmentdb: url: jdbc:hsqldb:file:testdb username: sa password:---spring: profiles: testdb: 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 應用程式SpringBoot非常適合於開發基於SpringMVC 的 Web 應用程式。通過內嵌的 Tomcat 或 Jetty 伺服器,可以簡化對 Web 應用程式的部署。SpringBoot通過自動設定功能對SpringMVC 應用做了一些基本的配置,使其更加適合一般 Web 應用程式的開發要求。
HttpMessageConverterSpring MVC 中使用 HttpMessageConverter 介面來在 HTTP 要求和響應之間進行訊息格式的轉換。預設情況下已經通過 Jackson 支援 JSON 和通過 JAXB 支援 XML 格式。可以通過建立自訂 HttpMessageConverters 的方式來添加其他的訊息格式轉換實現。
靜態檔案預設情況下,SpringBoot可以對 “/static”、“/public”、“/resources” 或 “/META-INF/resources” 目錄下的靜態檔案提供支援。同時SpringBoot還支援 Webjars。路徑“/webjars/**”下的內容會由 webjar 格式的 Jar 包來提供。
生產環境營運支援與開發與測試環境不同的是,當應用部署到生產環境時,需要各種營運相關的功能的支援,包括效能指標、運行資訊和應用管理等。所有這些功能都有很多技術和開 源庫可以實現。SpringBoot對這些營運相關的功能進行了整合,形成了一個功能完備和可定製的功能集,稱之為 Actuator。只需要在 POM 檔案中增加對 “org.springframe.boot:spring-boot-starter-actuator” 的依賴就可以添加 Actuator。Actuator 在添加之後,會自動暴露一些 HTTP 服務來提供這些資訊。這些 HTTP 服務的說明如表 2。表 2.SpringBootActuator 所提供的 HTTP 服務
名稱
說明 是否包含敏感資訊1.autoconfig 顯示SpringBoot自動設定的資訊。 是2.beans 顯示應用中包含的Springbean 的資訊。 是3.configprops 顯示應用中的配置參數的實際值。 是4.dump 產生一個 thread dump。 是5.env 顯示從 ConfigurableEnvironment 得到的環境配置資訊。 是6.health 顯示應用的健康狀態資訊。 否7.info 顯示應用的基本資料。 否 對於表 2中的每個服務,通過訪問名稱對應的 URL 就可以擷取到相關的資訊。如訪問“/info”就可以擷取到 info 服務對應的資訊。服務是否包含敏感資訊說明了該服務暴露出來的資訊是否包含一些比較敏感的資訊,從而確定是否需要添加相應的存取控制,而不是對所有人都公 開。所有的這些服務都是可以配置的,比如通過改變名稱來改變相應的 URL。下面對幾個重要的服務進行介紹。
health 服務SpringBoot預設提供了對應用本身、關聯式資料庫串連、MongoDB、Redis 和 Rabbit MQ 的健康狀態的檢測功能。當應用中添加了 DataSource 類型的 bean 時,SpringBoot會自動在 health 服務中暴露資料庫連接的資訊。應用也可以提供自己的健康狀態資訊,如代碼執行個體7 所示。
執行個體7. 自訂 health 服務@Componentpublic 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 FirstSpringBootApplicationinfo.app_version=1.0.0當訪問“/info”時,訪問的 JSON 資料如代碼執行個體10 所示。
執行個體10. Info 服務返回的結果{"app_name":"My FirstSpringBootApplication","app_version":"1.0.0"}
metrics 服務當訪問 metrics 服務時,可以看到SpringBoot通過 SystemPublicMetrics 預設提供的一些系統的績效參數值,包括記憶體、CPU、Java 類載入和線程等的基本資料。應用可以記錄其他所需要的資訊。SpringBoot預設提供了兩種類型的效能指標記錄方式:gauge 和 counter。gauge 用來記錄單個絕對數值,counter 用來記錄增量或減量值。比如在一個 Web 應用程式中,可以用 counter 來記錄當前線上的使用者數量。當使用者登入時,把 counter 的值加 1;當使用者退出時,把 counter 的值減 1。代碼執行個體11 給出了一個樣本。
執行個體11. 自訂的 metrics 服務@RestControllerpublic class GreetingsController { @Autowired private CounterService counterService; @RequestMapping("/greet") public String greet() { counterService.increment("myapp.greet.count"); return "Hello!"; }}在代碼執行個體11 中添加了對SpringBoot提供的 CounterService 的依賴。當 greet 方法被調用時,會把名稱為“myapp.greet.count”的計數器的值加 1。也就是當使用者每次訪問“/greet”時,該計算機就會被加 1。除了 CounterService 之外,還可以使用 GaugeService 來記錄絕對值。
使用 JMX 進行管理添加 Actuator 後所暴露的 HTTP 服務只能提供唯讀資訊。如果需要對應用在運行時進行管理,則需要用到 JMX。SpringBoot預設提供了 JMX 管理的支援。只需要通過 JDK 內建的 JConsole 串連到應用的 JMX 伺服器,就可以看到在域“org.springframework.boot”中 mbean。可以通過Spring提供的 @ManagedResource、@ManagedAttribute 和 @ManagedOperation 註解來建立應用自己的 mbean。
使用SpringBootCLISpringBoot提供了命令列工具來運行 Groovy 檔案。命令列工具的安裝非常簡單,只需要下載之後解壓縮即可。見參考資源。解壓之後可以運行Spring命令來使用該工具。通過 Groovy 開發的應用與使用 Java 並沒有差別,只不過使用 Groovy 簡化的文法可以使得代碼更加簡單。代碼執行個體12 給出了與代碼執行個體2 功能相同的 Groovy 實現。
執行個體12. 使用 Groovy 的樣本應用@RestControllerclass WebApplication { @RequestMapping("/") String home() { "Hello World!" }}只需要使用“spring run app.groovy”就可以運行該應用。還可以使用 Groovy 提供的 DSL 支援來簡化應用,如代碼執行個體13 所示。
執行個體13. 使用 Groovy DSL 簡化應用@RestControllerclass 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 可以快速建立和配置Springbean。對於廣大使用Spring架構的開發人員來說,SpringBoot無疑是一個非常實用的工具。本文詳細介紹了如何通過SpringBoot快速建立 Spring應用以及它所提供的自動設定和外部化配置的能力,同時還介紹了SpringBoot內建的 Actuator 提供的可以在生產環境中直接使用的效能指標、運行資訊和應用管理等功能,最後介紹了SpringBoot命令列工具的使用。通過基於依賴的自動設定功能, 使得Spring應用的配置變得非常簡單。在依賴的管理上也變得更加簡單,不需要開發人員自己來進行整合。Actuator 所提供的功能非常實用,對於在生產環境下對應用的監控和管理是大有好處的。SpringBoot應該成為每個使用Spring架構的開發人員使用的工具。
使用SpringBoot快速構建Spring架構應用