服务注册与发现

本指南将引导您启动和使用 Netflix Eureka 服务注册中心。

您将构建什么

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

您需要什么

  • 约 15 分钟

  • 一个您喜欢的文本编辑器或 IDE

  • Java 17 或更高版本

如何完成本指南

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

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

从 Spring Initializr 开始

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

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

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

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

手动初始化 Eureka Server 项目

  1. 导航到 https://start.spring.io。此服务会引入应用程序所需的所有依赖项,并为您完成大部分设置工作。

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

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

  4. 点击 Generate

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

手动初始化服务 A 和服务 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 Server。您可以使用 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 server。

与注册中心通信

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

服务 A

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

服务 B

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

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

应用程序运行后,您可以查看 Eureka dashboard

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 Dashboard,观察到 serviceaserviceb 已注册

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

  • 观察输出,应为 Hello world from Service A!

serviceaserviceb 注册自身并从注册中心刷新实例需要一点时间。如果 curl 命令最初失败,请稍等一分钟再试。

总结

恭喜!您已成功使用 Spring 启动了一个 Netflix Eureka 服务注册中心并在客户端应用程序中使用了该注册中心。

另请参阅

以下指南可能也有帮助

想编写新的指南或为现有指南做出贡献?请查看我们的贡献指南

所有指南的代码均采用 ASLv2 许可发布,文字内容采用 署名-禁止演绎创意共享许可协议

获取代码