在本文中,我们将学习 Spring Cloud Netflix Eureka 中的服务器端和客户端服务发现。通过使用中央注册服务,我们可以发现为我们的网络应用提供服务的所有微服务,以及它们在启动时各自占用的端口号。这种中央注册服务就是所谓的 Spring Cloud Netflix Eureka 服务器。Eureka 服务器的唯一目的就是发现服务。每个在 Eureka 服务器注册的微服务都会定期向 Eureka 服务器发送各自的状态更新。
这样,Eureka 服务器就能不断更新每个服务的状态(服务是否正常运行)。它还能跟踪每个服务实例正在处理的请求数量,这在微服务的负载平衡方面发挥着重要作用。
微服务
在采用微服务式软件开发之后,还需要开发一些额外的组件。我们已经看到了单个网络应用程序是如何被分解成更小的部分(服务)的。随着未来新需求的出现,网络应用程序所需的服务数量也会增加。随着按照这种软件开发模式开发的微服务越来越多,我们需要一个中心位置来跟踪这些服务。
这样,就能更容易地确定哪些服务当前已启动并正在运行,哪些服务在应用程序运行时未能启动。
需要:
- Project: Maven
- Language: Java
- Java Version: 11
- Packaging: Java Archive
- IDE: Eclipse (with Spring Tool Suite installed)
- Configuring the Eureka Server
在我们的示例中,我们将设置一个Eureka服务器和2个示例服务,这些服务将在Eureka服务器上进行注册,以实现服务发现机制的目的。这两个示例服务是购物车服务和用户服务。用户通过调用用户服务的端点来请求一个特定的item_id,然后调用购物车服务,购物车服务会将该item_id的请求放入库存中。为了创建这些服务,我们将使用 Eclipse IDE 提供的 Spring Starter Project 实用程序。
主程序:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableEurekaClient @EnableFeignClients public class UserServiceApplication { public static void main(String[] args) { SpringApplication.run(UserServiceApplication.class, args); } }
|
- @SpringBootApplication 注解用于设置 Spring Boot 的自动配置功能,以及调用组件扫描机制来扫描相应的组件。
- @EnableEurekaClient 注解指定此服务为客户端服务,将在 Eureka 服务器上注册,用于服务发现过程。
- @EnableFeignClients 注解用于调用已在相应 Eureka 服务器注册的另一个微服务端点。
控制器:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import com.elkstack.feign.Feign; @RestController public class UserController { @Autowired Feign feign; @GetMapping("/add/{item_id}") public String addUsersItem(@PathVariable("item_id") String item_id) { feign.addToCart(item_id); return "Item with id: " + item_id + " selected to add in cart" ; } }
|
- @RestController 注解用于表示该类各端点作为输出返回的 Java 对象将自动序列化和反序列化为 JSON 格式。
- 这里的 @Autowired 注解用于初始化 Feign 接口对象,以便调用在 Eureka 服务器注册的另一个微服务。
- Feign 接口用于调用将被调用的服务的相应端点。
- 端点 /add/{item_id} 将以 @PathVariable 注解的形式接收 item_id 作为输入。
- addToCart() 方法是属于购物车服务的方法,负责接收输入的 item_id,然后将其放入示例用户购物车的订单请求。
配置Feign
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name="CartService") public interface Feign { @GetMapping("/addToCart/{item_id}") public String addToCart(@PathVariable("item_id") String item_id); }
|
- @FeignClient 注解用于将此 Feign 接口注释为接口,该接口将用于提供通过 Cart 服务的 /addToCart/{item_id} 端点调用 Cart 服务的 addToCart() 方法的功能。
- 然后,购物车服务接收输入的 item_id,并将用户提出的 item_id 请求放入库存。
application.properties
spring.application.name=UserService server.port=8090 eureka.instance.preferIpAddress = true eureka.client.registerWithEureka = true eureka.client.fetchRegistry = true eureka.client.serviceUrl.defaultZone = http://localhost:8761/eureka
|
- eureka.client.serviceUrl.defaultZone属性包含注册其余所有微型服务的eureka服务器URL。
- 用户服务通过eureka.client.registerWithEureka属性向Eureka服务器注册
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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.16</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>elkstackmumbai</groupId> <artifactId>UserService</artifactId> <version>0.0.1-SNAPSHOT</version> <name>UserService</name> <description>User Service MicroService</description> <properties> <java.version>17</java.version> <spring-cloud.version>2021.0.8</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
</project>
|
Maven 依赖
- Spring Web
- Spring Netflix Eureka Client
- OpenFeign
Cart Service
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication @EnableEurekaClient public class CartServiceApplication {
public static void main(String[] args) { SpringApplication.run(CartServiceApplication.class, args); }
}
|
在上述代码片段中
- @SpringBootApplication 注解用于设置 Spring Boot 的自动配置功能,以及调用组件扫描机制来扫描相应的组件。
- @EnableEurekaClient 注解指定此服务为客户端服务,将在 Eureka 服务器上注册,用于服务发现过程。
控制器
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController;
@RestController public class CartServiceController {
@GetMapping("/addToCart/{item_id}") public String addToCart(@PathVariable("item_id") String item_id) { return "Item with id : " + item_id+ "added to cart"; } }
|
- @RestController 注解表示该类各端点作为输出返回的 Java 对象将自动序列化和反序列化为 JSON 格式。
- 端点 /addToCart/{item_id} 将通过 OpenFeign 机制从用户服务接收的 item_id 作为 @PathVariable 注解形式的输入。
- addToCart() 方法只需接收输入的 item_id,并将其作为输出返回,然后显示相应 item_id 已成功添加到购物车的信息。
application.properties
server.port=8095 spring.application.name=CartService eureka.instance.preferIpAddress = true eureka.client.registerWithEureka = true eureka.client.fetchRegistry = true eureka.client.serviceUrl.defaultZone = http://localhost:8761/eureka
|
- eureka.client.serviceUrl.defaultZone 属性包含注册其余所有微型服务的 eureka 服务器 URL。
- 用户服务通过 eureka.client.registerWithEureka 属性向 Eureka 服务器注册。
pom.xml Cart Service
<?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.7.16</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>elkstackmumbai</groupId> <artifactId>cartservice</artifactId> <version>0.0.1-SNAPSHOT</version> <name>CartService</name> <description>Cart Service App</description> <properties> <java.version>17</java.version> <spring-cloud.version>2021.0.8</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
|
依赖:
- Spring Web
- Spring Netflix Eureka Client
创建 Eureka Server
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication @EnableEurekaServer public class EurekaApplication {
public static void main(String[] args) { SpringApplication.run(EurekaApplication.class, args); }
}
|
- @SpringBootApplication 注解用于设置 Spring Boot 的自动配置功能,以及调用组件扫描机制来扫描相应的组件。
- @EnableEurekaServer 注解指定该服务为 Eureka 服务器,所有其他微服务都将注册到该服务器上,以便在服务发现过程中充当中央注册中心。
application.properties
spring.application.name=Eureka server.port=8761 eureka.instance.hostname=localhost eureka.client.registerWithEureka=false eureka.client.fetchRegistry=false eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka
|
- eureka.client.serviceUrl.defaultZone属性包含Eureka服务器URL值和端口号,该Eureka服务器已被设置到该端口号上。
- 其余服务将在该 Eureka 服务器上注册,现在该服务将成为所有其他微服务的中心注册点。
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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.16</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>elkstackmumbai</groupId> <artifactId>EurekaService</artifactId> <version>0.0.1-SNAPSHOT</version> <name>Eureka</name> <description>Eureka Central Registry Service</description> <properties> <java.version>17</java.version> <spring-cloud.version>2021.0.8</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
|
依赖于
- Spring Netflix Eureka Server
最后步骤
创建这些 Spring Boot 项目后,我们就可以通过 Postman 访问端点:http://localhost:8090/add/2
通过中央注册中心Eureka Server查看注册的服务
点击端点:http://localhost:8761/
- 这将打开Eureka 服务器仪表板
- 我们可以看到注册到Eureka Server的Services
- 注册到 Eureka Server 的 User Service、Cart Service 这 2 个服务以及它们当前启动和运行的端口号都显示在其中。购物车服务正在端口号上运行:8095。同时,用户服务正在端口号上运行:8090。
这样我们就可以准确地识别出哪些服务由于可能出现的故障而尚未注册到Eureka服务器上防止给定的服务在应用程序启动时启动并运行。
结论
正如我们通过上面的代码示例看到的,我们如何设置服务并将其注册到 Eureka 服务器。使用这个Eureka服务器,我们能够查看所有注册到它的服务,并完成我们在微服务环境中的服务发现过程。