使用 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 构建应用时,可使用任何你喜欢的构建程序。此处包含的代码须要经过 Gradle 或 Maven 来运行。若是还不熟悉它们,请参阅 使用 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

译者:万想

 

相关文章
相关标签/搜索