使用 Spring Boot Actuator 構建 RESTful Web 應用

Spring Boot Actuator 是 Spring Boot 的一個子項目。經過它,能夠很輕易地爲應用提供多種生產級服務。本教程中,你將經過構建一個應用來學習如何添加這些服務。html

1. 你須要構建什麼

本教程將帶你使用 Spring Boot Actuator 建立一個 「hello world」 RESTful Web 服務。你須要構建一個 HTTP GET 請求服務:java

$ curl http://localhost:9000/hello-world
複製代碼

返回如下 JSONgit

{"id":1,"content":"Hello, World!"}
複製代碼

它們也向你的應用中增長了不少開箱即用的、可在生產(或其餘)環境管理服務的功能。你所構建的服務,其業務功能與 構建 RESTful Web 應用 教程結果相一致。儘管比較結果可能頗有趣,但也無需爲了學習而學習此教程。github

1.1. 你須要準備什麼

2. 如何完成本教程

像大多數 Spring 入門指南 同樣,你能夠從頭開始並完成每一步,也能夠跳過已經熟悉的基礎配置環節。不管如何,最終都會獲得可正常工做的代碼。web

從頭開始,請移步 使用 Gradle 構建 章節spring

跳過基礎環節,請執行如下步驟:shell

  • 下載 並解壓本教程的源代碼,或使用 Git 進行 clone: git clone https://github.com/spring-guides/gs-actuator-service.git
  • 進入 gs-actuator-service/initial 目錄
  • 向前跳轉至 建立表現類 章節

結束後,能夠根據 gs-actuator-service/complete 目錄下的代碼來檢查結果。express

3. 使用 Gradle 構建

首先,設置一個基本的構建腳本。在使用 Spring 構建應用時,可使用任何你喜歡的構建程序。此處包含的代碼須要經過 GradleMaven 來運行。若是還不熟悉它們,請參閱 使用 Gradle 構建 Java 項目使用 Maven 構建 Java 項目apache

3.1. 建立目錄結構

在工做目錄中,建立以下所示的子目錄結構;例如,在類 UNIX 系統中,可以使用 mkdir -p src/main/java/hello 命令建立。json

└── src
    └── main
        └── java
            └── hello
複製代碼

3.2. 建立 Gradle 構建腳本

下面是 Gradle 初始化構建腳本

build.gradle
buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.6.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

bootJar {
    baseName = 'gs-actuator-service'
    version =  '0.1.0'
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.springframework.boot:spring-boot-starter-actuator")
    testCompile("org.springframework.boot:spring-boot-starter-test")
    testCompile("junit:junit")
}
複製代碼

Spring Boot Gradle 插件 提供了不少方便的功能:

  • 聚集 classpath 下的全部 jar 包依賴,並構建一個可執行的單體 「über-jar」,這將使執行和傳輸你的服務變得更加方便。
  • 搜索 public static void main() 方法所在的類,並將其標記爲可執行類。
  • 提供一個內置有 Spring Boot 依賴 匹配版本號集合的依賴解析器。你也能夠重寫爲任意版本,但它默認爲 Spring Boot 所選的版本號集合。

4. 使用 Maven 構建

首先,設置一個基本的構建腳本。在使用 Spring 構建應用時,可使用任何你喜歡的構建程序。此處包含的代碼須要經過 Maven 來運行。若是還不熟悉它,請參閱 使用 Maven 構建 Java 項目

4.1. 建立目錄結構

在工做目錄中,建立以下所示的子目錄結構;例如,在類 UNIX 系統中,可以使用 mkdir -p src/main/java/hello 命令建立。

└── src
    └── main
        └── java
            └── hello
pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>gs-actuator-service</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
複製代碼

Spring Boot Maven 插件 提供了不少方便的功能:

  • 聚集 classpath 下的全部 jar 包依賴,並構建一個可執行的單體 「über-jar」,這使得執行和傳輸你的服務變得更加方便。
  • 搜索 public static void main() 方法所在的類,並將其標記爲可執行類。
  • 提供一個內置有 Spring Boot 依賴 匹配版本號集合的依賴解析器。你也能夠重寫爲任意版本,但它默認爲 Spring Boot 所選的版本號集合。

5. 使用 IDE 構建

6. 運行空服務

對初學者來講,這兒有一個空白的 Spring MVC 應用。

src/main/java/hello/HelloWorldApplication.java
package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class HelloWorldApplication {

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

}
複製代碼

@SpringBootApplication 註解提供了一些默認值(如嵌入式 Servlet 容器),固然,這取決於你 classpath 下的內容和其餘內容。同時,還開啓了 Spring MVC 的 @EnableWebMvc 註解,以激活 Web 端點。

程序中沒有定義任何端點,但它已足夠啓動並觀察 Actuator 的一些功能。 SpringApplication.run() 命令知道如何啓動 Web 應用。你只須要運行此命令便可。

$ ./gradlew clean build && java -jar build/libs/gs-actuator-service-0.1.0.jar
複製代碼

你幾乎沒有寫任何代碼,結果會發生什麼?等服務啓動好以後,打開另外一個 Terminal 終端來進行測試:

$ curl localhost:8080
{"timestamp":1384788106983,"error":"Not Found","status":404,"message":""}
複製代碼

服務器正在運行,而你並未定義任何業務端點。你能夠看到來自 Actuator /error 端點的通用 JSON 響應,而不是容器默認生成的 HTML 錯誤響應 。你可在服務啓動的控制檯日誌中看到暴露出來了哪些開箱即用的端點。例如:

$ curl localhost:8080/actuator/health
{"status":"UP"}
複製代碼

很好,服務已然 「UP」。

查看 Spring Boot Actuator 工程 以瞭解更多詳情。

7. 建立表現類

首先,考慮一下你的 API 會是什麼樣子。

你但願處理 /hello-world 的 GET 請求時,可使用 name 查詢參數。爲了響應這樣的請求,你將返回以下所示的 JSON 來表明一個問候語。

{
    "id": 1,
    "content": "Hello, World!"
}
複製代碼

id 字段是問候語的惟一標識,content 字段則是問候語的文本表示。

建立一個表示類來對問候語表示進行建模:

src/main/java/hello/Greeting.java
package hello;

public class Greeting {

    private final long id;
    private final String content;

    public Greeting(long id, String content) {
        this.id = id;
        this.content = content;
    }

    public long getId() {
        return id;
    }

    public String getContent() {
        return content;
    }

}
複製代碼

如今,你能夠建立一個爲表現類服務的控制器端點。

8. 建立資源控制器

在 Spring 中,REST 端點就是 Spring MVC 控制器。下面的 Spring MVC 控制器處理了 /hello-world 的 GET 請求,並返回 Greeting 資源:

src/main/java/hello/HelloWorldController.java
package hello;

import java.util.concurrent.atomic.AtomicLong;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloWorldController {

    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();

    @GetMapping("/hello-world")
    @ResponseBody
    public Greeting sayHello(@RequestParam(name="name", required=false, defaultValue="Stranger") String name) {
        return new Greeting(counter.incrementAndGet(), String.format(template, name));
    }

}
複製代碼

面向用戶的控制器和 REST 端點控制器的關鍵區別在於如何建立響應。端點控制器不依賴視圖(例如JSP)來渲染 HTML 中的模型數據,而是簡單地將要寫入的數據直接返回到響應體中。

@ResponseBody 註解告訴 Spring MVC 不要將模型渲染到視圖中,而是將要返回的對象寫入響應體。渲染這一步驟將經過 Spring 消息轉換器來實現。Jackson 2 已在 classpath 中,這意味着,若是 Accept 請求頭指定應該返回 JSON,MappingJackson2HttpMessageConverter 將處理 Greeting 到 JSON 之間的轉換。

如何知道 Jackson 2 在 classpath 中呢?運行 mvn dependency:tree./gradlew dependencues 命令,將獲得詳細的依賴樹,並將顯示 Jackson 2.x。你還能夠看到它來自於 spring-boot-starter-json,其則是由 spring-boot-starter-web 依賴導入。

9. 建立可執行的 main 類

你能夠從自定義主類啓動應用,或者也能夠直接從其中一個配置類執行此操做。最簡單的辦法就是使用 SpringApplication 輔助類:

src/main/java/hello/HelloWorldApplication.java
package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class HelloWorldApplication {

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

}
複製代碼

在傳統 Spring MVC 應用中,你須要經過添加 @EnableWebMvc 註解來打開包括 DispatcherServlet 在內的關鍵特性。當 Spring Boot 在 classpath 中檢測到 spring-webmvc 時,會自動打開此註解。這將使你在接下來的步驟中能夠更方便地構建控制器。

@SpringBootApplication 還引入了 @ComponentSacn 註解,來告訴 Spring 掃描 hello 包,並加載那些控制器(以及其餘被標註了註解的組件類)。

10. 構建可執行 JAR

你能夠在命令行中經過 Gradle 或 Maven 來運行應用,也能夠構建並運行一個包含了必要依賴、類和資源文件的可執行 JAR 包。這將使在整個開發生命週期中,跨不一樣環境應用程序發佈、版本和部署更爲容易。

若是你使用的是 Gradle,能夠經過 ./gradlew bootRun 來啓動應用;也可經過 ./gradlew build 來構建 JAR 包,並經過下述命令運行之:

java -jar build/libs/gs-actuator-service-0.1.0.jar
複製代碼

若是你使用的是 Maven,能夠經過 ./mvnw spring-boot:run 來啓動應用;也可經過 ./mvnw clean package 來構建 JAR 包,並經過下述命令運行之:

java -jar target/gs-actuator-service-0.1.0.jar
複製代碼

上述兩種方式將建立一個可執行 JAR 包,你也能夠 構建一個經典 WAR 包

... service comes up ...
複製代碼

測試一下:

$ curl localhost:8080/hello-world
{"id":1,"content":"Hello, Stranger!"}
複製代碼

11. 切換到其餘端口

Spring Boot Actuator 默認運行在 8080 端口,經過添加 application.properties 文件能夠覆蓋該配置。

src/main/resources/application.properties
server.port: 9000
management.server.port: 9001
management.server.address: 127.0.0.1
複製代碼

重啓應用:

$ ./gradlew clean build && java -jar build/libs/gs-actuator-service-0.1.0.jar

... service comes up on port 9000 ...
複製代碼

測試一下:

$ curl localhost:8080/hello-world
curl: (52) Empty reply from server
$ curl localhost:9000/hello-world
{"id":1,"content":"Hello, Stranger!"}
$ curl localhost:9001/actuator/health
{"status":"UP"}
複製代碼

12. 測試應用

爲了檢查應用程序是否能夠正常運行,你應該編寫應用程序的單元/集成測試類。可參照下面測試案例:

  • 控制器是否正常
  • 管理端點是否正常

正如在測試類中所看到的那樣,咱們在隨機端口啓動應用。

src/test/java/hello/HelloWorldApplicationTests.java
/*
 * Copyright 2012-2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package hello;

import java.util.Map;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;

import static org.assertj.core.api.BDDAssertions.then;

/**
 * Basic integration tests for service demo application.
 *
 * @author Dave Syer
 */
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = {"management.port=0"})
public class HelloWorldApplicationTests {

    @LocalServerPort
    private int port;

    @Value("${local.management.port}")
    private int mgt;

    @Autowired
    private TestRestTemplate testRestTemplate;

    @Test
    public void shouldReturn200WhenSendingRequestToController() throws Exception {
        @SuppressWarnings("rawtypes")
        ResponseEntity<Map> entity = this.testRestTemplate.getForEntity(
                "http://localhost:" + this.port + "/hello-world", Map.class);

        then(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
    }

    @Test
    public void shouldReturn200WhenSendingRequestToManagementEndpoint() throws Exception {
        @SuppressWarnings("rawtypes")
        ResponseEntity<Map> entity = this.testRestTemplate.getForEntity(
                "http://localhost:" + this.mgt + "/actuator/info", Map.class);

        then(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
    }

}
複製代碼

13. 總結

恭喜你,你已用 Spring 開發了一個簡單的 RESTful 服務。正由於 Spring Boot Actuator,你添加了一些有用的內置服務。

14. 參考

如下教程也可能對你有所幫助:

想要撰寫新的教程或者是爲現有的教程進行完善?請查看咱們的 貢獻指南

全部已發佈的教程均爲代碼提供 ASLv2 許可協議,爲正文提供 CC BY-ND 3.0 許可協議。


原文:spring.io/guides/gs/a…

做者:spring.io

譯者:萬想

相關文章
相關標籤/搜索