A Quick Guide to Spring Cloud Consul – Spring的云领事的快速指南

最后修改: 2017年 12月 7日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

The Spring Cloud Consul project provides easy integration with Consul for Spring Boot applications.

Spring Cloud Consul项目为Spring Boot应用程序提供了与Consul的轻松集成。

Consul is a tool that provides components for resolving some of the most common challenges in a micro-services architecture:

Consul是一个工具,它提供了用于解决微服务架构中一些最常见挑战的组件。

  • Service Discovery – to automatically register and unregister the network locations of service instances
  • Health Checking – to detect when a service instance is up and running
  • Distributed Configuration – to ensure all service instances use the same configuration

In this article, we’ll see how we can configure a Spring Boot application to use these features.

在这篇文章中,我们将看到如何配置Spring Boot应用程序以使用这些功能。

2. Prerequisites

2.先决条件

To start with, it’s recommended to take a quick look at Consul and all its features.

首先,建议快速浏览一下Consul和它的所有功能。

In this article, we’re going to use a Consul agent running on localhost:8500. For more details about how to install Consul and run an agent, refer to this link.

在这篇文章中,我们将使用一个运行在localhost:8500上的Consul代理。关于如何安装Consul和运行代理的更多细节,请参考这个链接

First, we’ll need to add the spring-cloud-starter-consul-all dependency to our pom.xml:

首先,我们需要将spring-cloud-starter-consul-all依赖性添加到我们的pom.xml

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-all</artifactId>
    <version>3.1.1</version>
</dependency>

3. Service Discovery

3.服务发现

Let’s write our first Spring Boot application and wire up with the running Consul agent:

让我们编写第一个Spring Boot应用程序,并与正在运行的Consul代理进行连接。

@SpringBootApplication
public class ServiceDiscoveryApplication {

    public static void main(String[] args) {
        new SpringApplicationBuilder(ServiceDiscoveryApplication.class)
          .web(true).run(args);
    }
}

By default, Spring Boot will try to connect to the Consul agent at localhost:8500. To use other settings, we need to update the application.yml file:

默认情况下,Spring Boot将尝试在localhost:8500连接到Consul代理。要使用其他设置,我们需要更新application.yml文件。

spring:
  cloud:
    consul:
      host: localhost
      port: 8500

Then, if we visit the Consul agent’s site in the browser at http://localhost:8500, we’ll see that our application was properly registered in Consul with the identifier from “${spring.application.name}:${profiles separated by comma}:${server.port}”.

然后,如果我们在浏览器中访问Consul代理的网站http://localhost:8500,我们会看到我们的应用程序已经在Consul中正确注册,标识符来自“${spring.application.name}:${profiles separated by comma}:${server.port}”

To customize this identifier, we need to update the property spring.cloud.discovery.instanceId with another expression:

为了定制这个标识符,我们需要用另一个表达式更新属性spring.cloud.discovery.instanceId

spring:
  application:
    name: myApp
  cloud:
    consul:
      discovery:
        instanceId: ${spring.application.name}:${random.value}

If we run the application again, we’ll see that it was registered using the identifier “MyApp” plus a random value. We need this for running multiple instances of our application on our local machine.

如果我们再次运行该应用程序,我们会看到它是用标识符“MyApp”加上一个随机值注册的。我们需要这个来在本地机器上运行我们的应用程序的多个实例。

Finally, to disable Service Discovery, we need to set the property spring.cloud.consul.discovery.enabled to false.

最后,为了禁用服务发现,我们需要将属性spring.cloud.consul.discovery.enabled设置为false

3.1. Looking Up Services

3.1.查阅服务

We already have our application registered in Consul, but how can clients find the service endpoints? We need a discovery client service to get a running and available service from Consul.

我们已经在Consul中注册了我们的应用程序,但客户端如何找到服务端点?我们需要一个发现客户端服务来从Consul中获得一个正在运行的可用服务。

Spring provides a DiscoveryClient API for this, which we can enable with the @EnableDiscoveryClient annotation:

Spring为此提供了一个DiscoveryClient API,我们可以用@EnableDiscoveryClient注解来启用它。

@SpringBootApplication
@EnableDiscoveryClient
public class DiscoveryClientApplication {
    // ...
}

Then, we can inject the DiscoveryClient bean into our controller and access the instances:

然后,我们可以将DiscoveryClient Bean注入我们的控制器并访问实例。

@RestController
public class DiscoveryClientController {
 
    @Autowired
    private DiscoveryClient discoveryClient;

    public Optional<URI> serviceUrl() {
        return discoveryClient.getInstances("myApp")
          .stream()
          .findFirst() 
          .map(si -> si.getUri());
    }
}

Finally, we’ll define our application endpoints:

最后,我们将定义我们的应用程序端点。

@GetMapping("/discoveryClient")
public String discoveryPing() throws RestClientException, 
  ServiceUnavailableException {
    URI service = serviceUrl()
      .map(s -> s.resolve("/ping"))
      .orElseThrow(ServiceUnavailableException::new);
    return restTemplate.getForEntity(service, String.class)
      .getBody();
}

@GetMapping("/ping")
public String ping() {
    return "pong";
}

The “myApp/ping” path is the Spring application name with the service endpoint. Consul will provide all available applications named “myApp”.

“myApp/ping”路径是具有服务端点的Spring应用程序名称。Consul将提供所有可用的名为“myApp “的应用程序

4. Health Checking

4.健康检查

Consul checks the health of the service endpoints periodically.

Consul定期检查服务端点的健康状况。

By default, Spring implements the health endpoint to return 200 OK if the app is up. If we want to customize the endpoint we have to update the application.yml:

默认情况下,Spring实现了健康端点,如果应用程序已启动,则返回200 OK。如果我们想定制这个端点,我们必须更新application.yml:

spring:
  cloud:
    consul:
      discovery:
        healthCheckPath: /my-health-check
        healthCheckInterval: 20s

As a result, Consul will poll the “/my-health-check” endpoint every 20 seconds.

因此,Consul将每20秒轮询一次“/my-health-check” 端点。

Let’s define our custom health check service to return a FORBIDDEN status:

让我们定义我们的自定义健康检查服务,以返回一个FORBIDDEN状态。

@GetMapping("/my-health-check")
public ResponseEntity<String> myCustomCheck() {
    String message = "Testing my healh check function";
    return new ResponseEntity<>(message, HttpStatus.FORBIDDEN);
}

If we go to the Consul agent site, we’ll see that our application is failing. To fix this, the “/my-health-check” service should return the HTTP 200 OK status code.

如果我们去Consul代理网站,我们会看到我们的应用程序正在失败。为了解决这个问题,“/my-health-check”服务应该返回HTTP 200 OK状态代码。

5. Distributed Configuration

5.分布式配置

This feature allows synchronizing the configuration among all the services. Consul will watch for any configuration changes and then trigger the update of all the services.

这个功能允许在所有服务中同步配置。Consul将观察任何配置变化,然后触发所有服务的更新。

First, we need to add the spring-cloud-starter-consul-config dependency to our pom.xml:

首先,我们需要将spring-cloud-starter-consul-config依赖性添加到我们的pom.xml

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-config</artifactId>
    <version>3.1.1</version>
</dependency>

We also need to move the settings of Consul and Spring application name from the application.yml file to the bootstrap.yml file which Spring loads first.

我们还需要将Consul和Spring应用程序名称的设置从application.yml文件移到Spring首先加载的bootstrap.yml文件。

Then, we need to enable Spring Cloud Consul Config:

然后,我们需要启用Spring Cloud Consul配置。

spring:
  application:
    name: myApp
  cloud:
    consul:
      host: localhost
      port: 8500
      config:
        enabled: true

Spring Cloud Consul Config will look for the properties in Consul at “/config/myApp”. So if we have a property called “my.prop”, we would need to create this property in the Consul agent site.

Spring Cloud Consul配置将在Consul中寻找“/config/myApp”/em>的属性。因此,如果我们有一个名为“my.prop”的属性,我们将需要在Consul代理站点中创建这个属性。

We can create the property by going to the “KEY/VALUE” section, then entering “/config/myApp/my/prop” in the “Create Key” form and “Hello World” as value. Finally, click the “Create” button.

我们可以通过进入“KEY/VALUE”部分,然后在“Create Key”表格中输入“/config/myApp/my/prop”“Hello World”作为值来创建该属性。最后,点击“创建”按钮。

Bear in mind that if we are using Spring profiles, we need to append the profiles next to the Spring application name. For example, if we are using the dev profile, the final path in Consul will be “/config/myApp,dev”.

请记住,如果我们使用Spring配置文件,我们需要在Spring应用程序名称旁边附加配置文件。例如,如果我们使用dev配置文件,Consul的最终路径将是“/config/myApp,dev”.

Now, let’s see what our controller with the injected properties looks like:

现在,让我们看看注入了属性的控制器是什么样子的。

@RestController
public class DistributedPropertiesController {

    @Value("${my.prop}")
    String value;

    @Autowired
    private MyProperties properties;

    @GetMapping("/getConfigFromValue")
    public String getConfigFromValue() {
        return value;
    }

    @GetMapping("/getConfigFromProperty")
    public String getConfigFromProperty() {
        return properties.getProp();
    }
}

And the MyProperties class:

还有MyProperties类。

@RefreshScope
@Configuration
@ConfigurationProperties("my")
public class MyProperties {
    private String prop;

    // standard getter, setter
}

If we run the application, the field value and properties have the same “Hello World” value from Consul.

如果我们运行应用程序,字段valueproperties具有来自Consul的相同“Hello World”值。

5.1. Updating the Configuration

5.1.更新配置

What about updating the configuration without restarting the Spring Boot application?

在不重启Spring Boot应用程序的情况下更新配置呢?

If we go back to the Consul agent site and we update the property “/config/myApp/my/prop” with another value like “New Hello World”, then the field value will not change and the field properties will have been updated to “New Hello World” as expected.

如果我们回到Consul代理站点,并将属性“/config/myApp/my/prop”更新为另一个值,如“New Hello World”,那么字段value将不会改变,字段properties将被更新为“New Hello World” 如预期。

This is because the field properties is a MyProperties class has the @RefreshScope annotation. All beans annotated with the @RefreshScope annotation will be refreshed after configuration changes.

这是因为字段propertiesMyProperties类具有@RefreshScope注解。所有用@RefreshScope注解的Bean都将在配置改变后被刷新。

In real life, we should not have the properties directly in Consul, but we should store them persistently somewhere. We can do this using a Config Server.

在现实生活中,我们不应该在Consul中直接拥有这些属性,但我们应该把它们持久地存储在某个地方。我们可以使用Config Server来做到这一点。

6. Conclusion

6.结论

In this article, we’ve seen how to set up our Spring Boot applications to work with Consul for Service Discovery purposes, customize the health checking rules and share a distributed configuration.

在这篇文章中,我们已经看到了如何设置我们的Spring Boot应用程序与Consul一起工作,以达到服务发现的目的,定制健康检查规则,并共享分布式配置。

We’ve also introduced a number of approaches for the clients to invoke these registered services.

我们还为客户引入了一些方法来调用这些注册服务。

As usual, sources can be found over on GitHub.

像往常一样,可以在GitHub上找到来源