Spring Boot 与 Docker
观察 GraphQL 的实际运行

本指南将引导您完成启动和使用 Netflix Eureka 服务注册表的过程。

你将构建什么

您将设置一个名为 eureka-serverNetflix Eureka 服务注册中心,然后构建两个名为 serviceaserviceb 的 Web 客户端,这两个客户端都将注册到 Eureka 服务器。其中一个 Web 客户端 serviceb 将使用 org.springframework.cloud.client.discovery.DiscoveryClientSpring Framework 的 Rest 客户端 调用另一个 Web 客户端 servicea

您需要什么

  • 大约15分钟
  • 一个喜欢的文本编辑器或IDE
  • Java 17 或更高版本

如何完成本指南

与大多数 Spring 入门指南 一样,您可以从头开始一步步完成每个步骤,也可以直接查看 此仓库 中的代码跳转到解决方案。

在本地环境中查看最终结果,您可以执行以下操作之一:

从 Spring Initializr 开始

对于所有 Spring 应用程序,您应该从 Spring Initializr 开始。Initializr 提供了一种快速的方式来引入应用程序所需的所有依赖项,并为您完成了大量的设置工作。

本指南需要三个应用程序。第一个应用程序(服务器应用程序)只需要 Eureka Server 依赖项。第二个和第三个应用程序(客户端应用程序)需要 Eureka Discovery Client 和 Spring Web 依赖项。

您可以使用以下链接从 Spring Initializr 获取预初始化的项目:

  • Eureka Server

  • Service A

  • Service B

由于本指南涉及的服务数量较多,GitHub 仓库中仅提供了解决方案。要从头开始,请使用上述链接或使用 Spring Initializr 生成空白项目,如下所述。

要手动初始化 Eureka Server 项目:

  1. 访问 https://start.spring.io。该服务会为您拉取应用程序所需的所有依赖项,并完成大部分设置工作。

  2. 选择 Gradle 或 Maven 以及您想要使用的编程语言。本指南假设您选择了 Maven 和 Java。

  3. 点击 Dependencies 并为服务器应用程序选择 Eureka Server

  4. 点击 Generate

  5. 下载生成的 ZIP 文件,这是一个根据您的选择配置好的 Web 应用程序归档文件。

要手动初始化 Service A 和 Service B 项目:

  1. 访问 https://start.spring.io。该服务会为您拉取应用程序所需的所有依赖项,并完成大部分设置工作。

  2. 选择 Gradle 或 Maven 以及您想要使用的语言。本指南假设您选择了 Maven 和 Java。

  3. 为客户端应用程序选择 Eureka Discovery ClientSpring Web

  4. 点击 Generate

  5. 下载生成的 ZIP 文件,这是一个根据您的选择配置好的 Web 应用程序归档文件。

如果您的 IDE 集成了 Spring Initializr,您可以直接在 IDE 中完成此过程。

启动 Eureka 服务注册中心

首先,您需要一个Eureka服务器。您可以使用Spring Cloud的@EnableEurekaServer来启动一个注册中心,其他应用程序可以通过该注册中心进行通信。这是一个普通的Spring Boot应用程序,只需添加一个注解(@EnableEurekaServer)即可启用服务注册中心。以下代码清单(来自eureka-server/src/main/java/com/example/eurekaserver/EurekaServerApplication.java)展示了服务器应用程序:

package com.example.eurekaserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

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

}

在生产环境中,您可能需要注册表的多个实例。您可以在这里找到有关配置 Eureka Server 的更多信息。

默认情况下,注册表也会尝试注册自身,因此您需要禁用此行为。此外,在本地使用时,将这个注册表放在一个单独的端口上是一个良好的惯例。

如下列清单所示,向 eureka-server/src/main/resources/application.yml 添加一些属性以满足这些需求:

spring:
  application:
    name: eureka-server
server:
  port: 8761
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
logging:
  level:
    com.netflix.eureka: OFF
    com.netflix.discovery: OFF

现在您可以通过运行 ./mvnw spring-boot:run 来启动 Eureka 服务器。

与注册表通信 {#_talking_to_the_registry}

现在您已经启动了服务注册中心,您可以启动与注册中心交互的客户端。我们的客户端应用程序 ServiceA 和 ServiceB 会自动注册到 Eureka 服务器,因为我们在类路径中包含了 spring-cloud-starter-netflix-eureka-client。为了避免端口冲突,请在 ServiceA 和 ServiceB 中设置 server.port 参数:

Service A:

spring:
  application:
    name: servicea
server:
  port: 8081

Service B:

spring:
  application:
    name: serviceb
server:
  port: 8082

此时,您应该能够运行所有三个应用程序。您可以使用 IDE 或在每个应用程序文件夹中执行 ./mvnw spring-boot:run 命令。

当应用程序运行时,您可以查看 Eureka 仪表盘

eureka server dashboard

服务A 端点

servicea 项目中创建一个名为 com/example/servicea/controller/ServiceARestController.java 的新类,以暴露一个可以用来测试应用程序的端点。

package com.example.servicea.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ServiceARestController {

    @GetMapping("/helloWorld")
    public String helloWorld() {
        return "Hello world from Service A!";
    }

}

服务B 端点

serviceb 项目中创建一个名为 com/example/serviceb/controller/ServiceBRestController.java 的新类,以公开一个调用 servicea 的端点。

package com.example.serviceb.controller;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestClient;

@RestController
public class ServiceBRestController {

    private final DiscoveryClient discoveryClient;
    private final RestClient restClient;

    public ServiceBRestController(DiscoveryClient discoveryClient, RestClient.Builder restClientBuilder) {
        this.discoveryClient = discoveryClient;
        restClient = restClientBuilder.build();
    }

    @GetMapping("helloEureka")
    public String helloWorld() {
        ServiceInstance serviceInstance = discoveryClient.getInstances("servicea").get(0);
        String serviceAResponse = restClient.get()
                .uri(serviceInstance.getUri() + "/helloWorld")
                .retrieve()
                .body(String.class);
        return serviceAResponse;
    }
}

该类使用 DiscoveryClient 仅基于应用程序名称来查找 serviceaserviceId。本指南中只有一个 servicea 实例,因此我们只需查看第一个实例。这体现在以下代码行中:

ServiceInstance serviceInstance = discoveryClient.getInstances("servicea").get(0);

一旦您拥有了一个指向 servicea 位置的 ServiceInstance,您现在就可以使用 Spring Framework 中的 Rest Client 信息了。

... = restClient.get().uri(serviceInstance.getUri() + "/helloWorld")...

您可以通过运行以下命令来测试所有三个应用程序:

curl http://localhost:8082/helloEureka

您应该会看到以下结果:

Hello world from Service A!

测试应用程序

本指南详细介绍了以下步骤(您可以通过实现本指南中展示的代码或使用解决方案仓库中的代码来完成这些步骤):

  • eureka-server 文件夹中运行 ./mvnw spring-boot:run 命令来启动 eureka-server

  • servicea 文件夹中运行 ./mvnw spring-boot:run 命令来启动 servicea

  • serviceb 文件夹中运行 ./mvnw spring-boot:run 命令来启动 serviceb

  • 通过访问 http://localhost:8761/ 查看 Eureka 仪表板,观察 serviceaserviceb 是否已注册

  • 运行 curl http://localhost:8082/helloEureka 命令来测试所有三个应用程序是否正常运行

  • 观察输出结果 Hello world from Service A!

serviceaserviceb 注册自身并从注册中心刷新实例时会有短暂的延迟。如果 curl 命令最初失败,请等待一分钟再试一次。

总结

恭喜!您刚刚使用 Spring 搭建了一个 Netflix Eureka 服务注册中心,并在客户端应用程序中使用了该注册中心。

另请参阅

以下指南可能也会有所帮助:

本页目录