SpringBoot 2 Actuator building RESTful Web services

The opening words

Spring Boot Actuator is Spring Boot subprojects. It adds several production-level service for your application, which does not require much effort you pay can be achieved. In this tutorial, you will build a application to add these services.
 

Your application will be created

The guide will guide you to create a "Hello, world" RESTful Web services using Spring Boot Actuator. We will build a HTTP GET request to accept service of the following:

$ curl http://localhost:9000/hello-world

It responds to the following JSON data:

{"id":1,"content":"Hello, World!"}

Application also added many features for the production (or other) environment management services. We build business function services and functions to build RESTful Web services are the same. Although the comparison may be very interesting, but we do not need to complete the guide means that guide.
 

Tools you will need

How to complete this guide

Like most of Spring Getting Started Like, you can start from scratch and complete each step, you can bypass you are already familiar with the basic setup steps. Such as which way on the code you can finally have a job.

  • To start from scratch, venue to start Initializr from the Spring ;
  • To skip foundation, do the following:
    • Download and decompress the guide used in the source code , or by means of its cloning operations Git:git clone https://github.com/spring-guides/gs-actuator-service.git
    • Switch to gs-actuator-service/initialthe directory;
    • Jump to the guidelines created to show classes .

After everything is ready, you can check gs-actuator-service/completethe code directory.

 

From the beginning of Spring Initializr

For all of Spring applications, you should from Spring Initializr start. Initializr provides a quick way to extract the required application depends, and completed a number of settings for you. The example requires Spring Boot Actuator and Spring Web dependent. The following figure shows the example provided Initializr item:
Spring Initializr interface

The figure shows the selection as Initializr Maven build tool. You can also use Gradle. It also com.exampleand actuator-servicevalues are shown as Group and Artifact. In the remainder of this example, these values will be used.

The following list shows the creation of the choice Maven pom.xmlfile:

<?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>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>actuator-service</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>actuator-service</name>
	<description>Demo project for Spring Boot</description>

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

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

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

</project>

The following list shows the creation of Gradle when selecting build.gradlefiles:

plugins {
	id 'org.springframework.boot' version '2.2.2.RELEASE'
	id 'io.spring.dependency-management' version '1.0.8.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-actuator'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

test {
	useJUnitPlatform()
}

 

Run empty Service

Spring Initializr create an empty application, we can use it to get started. The following example (from the initialcatalog src/main/java/com/example/actuatorservice/ActuatorServiceApplication) shows the class Spring Initializr created:

package com.example.actuatorservice;

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

@SpringBootApplication
public class ActuatorServiceApplication {

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

}

@SpringBootApplicationAnnotations provide a default value (e.g., an embedded servlet container) loading the contents of the classpath and other content. It also enabled the Spring MVC @EnableWebMvcannotation, the annotation will activate the Web endpoint.

Endpoint is not defined in this application, but there is enough to start the endpoint of things and see some of the features of the Actuator. SpringApplication.run()Command knows how to start the Web application. We need to do is run the following command:

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

由官网提供的以上这条命令的执行结果与我本地的不一样,我需要这样才能运行:./gradlew clean build && java -jar build/libs/actuator-service-0.0.1-SNAPSHOT.jar

我们尚未编写任何代码,打开另一个终端,然后尝试以下命令(及其输出显示):

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

以上命令的输出表明服务器正在运行,但是我们尚未定义任何业务端点。我们会看到来自 Actuator /error 端点的通用 JSON 响应,而不是默认的容器生成的 HTML 错误响应。我们可以在服务器启动的控制台日志中看到开箱即用提供的端点。我们可以尝试其中的一些端点,包括 /health 端点。以下示例显示了如何执行该操作:

$ curl localhost:8080/actuator/health
{"status":"UP"}

状态为 UP,因此 actuator 服务正在运行。

有关更多详细信息,请参见 Spring Boot 的 Actuator 项目
 

创建展示类

首先,我们需要考虑一下 API 的外观。

我们想要处理 /hello-world 的 GET 请求,可以选用使用名称查询参数。为了响应这样的请求,我们想发送回表示问候的 JSON,该 JSON 类似于以下内容:

{
    "id": 1,
    "content": "Hello, World!"
}

id 字段是问候语的唯一标识符,content 包含问候语的文本展示。

要建模问候展示,创建一个展示类。以下清单(来自 src/main/java/com/example/actuatorservice/Greeting.java)显示了 Greeting 类:

package com.example.actuatorservice;

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;
  }

}

现在,我们需要创建用于展示类的端点控制器。
 

创建资源控制器

在 Spring 中,REST 端点是 Spring MVC 控制器。以下 Spring MVC 控制器(来自 src/main/java/com/example/actuatorservice/HelloWorldController.java)处理针对 /hello-world 端点的 GET 请求并返回 Greeting 资源:

package com.example.actuatorservice;

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 在类路径中,因此如果请求的 Aceept 标头指定应返回 JSON,则 MappingJackson2HttpMessageConverterGreeting 对象转换成 JSON。

如何获知 Jackson 2 的类路径?运行 mvn dependency:tree./gradlew dependencies, 然后我们将获得包含 Jackson 2.x 的详细依赖关系树。我们还可以看到它来自 /spring-boot-starter-json,它本身是由 spring-boot-starter-web 导入的。
 

运行应用

我们可以从自定义主类或直接从其中一个配置类运行应用。对于这个简单的示例,可以使用 SpringApplication 帮助类。请注意,这是 Spring Initializr 为我们创建的应用类,我们甚至无需对其进行修改即可使其适用于该简单应用。以下清单(来自 src/main/java/com/example/actuatorservice/HelloWorldApplication.java)显示了应用类:

package com.example.actuatorservice;

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 在我们的类路径上监测到 spring-webmvc 时,它会自动开启该注解。这使我们可以在接下来的步骤中构建控制器。
@SpringBootApplication 注解还引入了 @ComponentScan 注解,该注解告诉 Spring 扫描 com.example.actuatorservice 应用包中的那些控制器(以及任何其他带有注解的组件类)。

构建可执行 JAR

我们可以结合 Gradle 或 Maven 来从命令行运行该应用。我们还可以构建一个包含所有必须依赖项、类以及资源的可执行 JAR 文件,然后运行该文件。在整个开发生命周期中,跨环境等等情况下,构建可执行 JAR 可以轻松地将服务作为应用进行发布、版本化以及部署。

如果使用 Gradle,则可以借助 ./gradlew bootRun 来运行应用。或通过借助 ./gradlew build 来构建 JAR 文件,然后运行 JAR 文件,如下所示:

java -jar build/libs/gs-actuator-service-0.1.0.jar

由官网提供的以上这条命令的执行结果与我本地的不一样,我需要这样才能运行:java -jar build/libs/actuator-service-0.0.1-SNAPSHOT.jar

如果使用 Maven,则可以借助 ./mvnw spring-boot:run 来运行该用。或可以借助 ./mvnw clean package 来构建 JAR 文件,然后运行 JAR 文件,如下所示:

java -jar target/gs-actuator-service-0.1.0.jar

由官网提供的以上这条命令的执行结果与我本地的不一样,我需要这样才能运行:java -jar target/actuator-service-0.0.1-SNAPSHOT.jar

我们还可以构建一个经典的 WAR 文件

服务运行后(因为我们在终端上运行 spring-boot:run),可以通过在单独的终端上运行以下命令来对其进行测试:

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

切换至不一样的服务器端口

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

由官网提供的以上这条命令的执行结果与我本地的不一样,我需要这样才能运行:./gradlew clean build && java -jar build/libs/actuator-service-0.0.1-SNAPSHOT.jar

现在,该服务从端口 9000 启动。

我们可以通过在终端中运行以下命令来测试它是否在端口 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"}

测试应用

要检查我们的应用是否正常工作,我们应该为应用编写单元测试和集成测试。src/test/java/com/example/actuatorservice/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 com.example.actuatorservice;

import java.util.Map;

import org.junit.jupiter.api.Test;

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 static org.assertj.core.api.BDDAssertions.then;

/**
 * Basic integration tests for service demo application.
 *
 * @author Dave Syer
 */
@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);
	}

}

 

概述

Congratulations! We just use Spring to develop a simple RESTful service, and use Spring Boot Actuator added some useful built-in service.
 

See also

The following guidelines may be helpful:

Want to see other content guidelines? Please visit this guide belongs to column: " the Spring Official Guide "

Published 103 original articles · won praise 6 · views 5046

Guess you like

Origin blog.csdn.net/stevenchen1989/article/details/104121103