微服务系列-基于Spring Cloud Eureka进行服务的注册与消费

公众号「架构成长指南」,专注于生产实践、云原生、分布式系统、大数据技术分享。

在之前的几个教程中,我们学了:

使用 RestTemplate 的 Spring Boot 微服务通信示例

使用 WebClient 的 Spring Boot 微服务通信示例

使用 Spring Cloud Open Feign 的 Spring Boot 微服务通信示例

在本教程中,我们将学习如何在Spring boot微服务项目中使用Spring Cloud Eureka进行服务注册与消费

服务注册和发现概述

在微服务项目中,我们一般会对一个项目,以业务的维度拆分至多个服务,比如用户服务、账务服务、订单服务、仓储服务等,这些服务在生产环境部署, 至少是2个服务实例,如果业务量大几十个都是有可能的。

试想这样一种场景

订单服务实例部署了4个,仓库服务部署了5个,仓库服务要调用订单服务,如果没有注册中心,他会怎么做,那只有把对应的ip和端口写死在代码中,如果新增了一个订单服务怎么办?或者下线了订单服务怎么办?

另外,在云环境中,服务实例随时都有可能启动和关闭,随之IP也会发生变化,没法把IP写死在代码中。

基于以上问题就有了服务注册中心Eureka

Eureka能实现服务自动的注册和发现,在每次服务调用的时候根据服务名称会获取到目标服务的IP和端口,在进行调用。

如果服务下线或者上线,对应的服务的地址信息也会进行更新,这样就保证了,随时可以调用到有效的服务。

同时为了提高性能,这个服务地址信息会在每个服务本地缓存一份地址信息表,定时更新,这样每次请求服务时,不用每次去Eureka查询来降低服务调用耗时。

在本教程中,我们将学习如何使用SpringCloud Eureka进行服务注册和发现,并通过OpenFeign进行服务的调用。

我们将做什么

我们部署一个Eureka Server,并将我们的微服务(部门服务和用户服务)作为 Eureka 客户端,注册到Eureka Server,同时使用用户服务调用根据部门服务的Service ID 来调用部门服务相关接口。

创建Eureka Server

1. 在 IntelliJ IDEA 中创建并设置 Spring boot 项目

让我们使用 springinitializr创建一个 Spring boot 项目。 请参阅下面的屏幕截图,在使用 springinitializr创建 Spring Boot 应用程序时输入详细信息 :

单击生成按钮以 zip 文件形式下载 Spring boot 项目。解压zip文件并在IntelliJ IDEA中导入Spring boot项目。 这是 pom.xml 文件供参考:

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.17</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>io.wz</groupId>
	<artifactId>eureka-server</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>eureka-server</name>
	<description>eureka-server</description>
	<properties>
		<java.version>1.8</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>
	</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>
				<configuration>
					<image>
						<builder>paketobuildpacks/builder-jammy-base:latest</builder>
					</image>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

2.添加@EnableEurekaServer注解

我们需要添加@EnableEurekaServer注解,使我们应用程序成为服务注册中心。

java 复制代码
package io.wz.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);
	}

}

3. 禁用Eureka Server作为Eureka Client

默认情况下,每个Eureka Server 也是一个Eureka客户端。由于我们只想让他做好服务注册中心,不想让他做客户端,因此我们将通过在application.properties文件中配置以下属性来禁用此客户端行为。

yaml 复制代码
spring.application.name=Eureka Server
server.port=8761
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

4.启动Eureka服务器

Eureka Server 提供了 UI,我们可以在其中看到有关注册服务的所有详细信息。 现在运行EurekaServerApplication并访问 http://localhost:8761,会显示以下界面

将Department-Service注册至Eureka Server

请参阅本教程创建 部门服务 和 用户服务 微服务: 使用 Spring Cloud Open Feign 的 Spring Boot 微服务通信示例

让我们将这个部门服务 作为 Eureka 客户端并向 Eureka 服务器注册。 将 Eureka client pom添加到部门服务中:

xml 复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

另外,添加 Spring Cloud 依赖项:

xml 复制代码
	<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>

添加版本属性:

xml 复制代码
	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>2021.0.4</spring-cloud.version>
	</properties>

在application.properties中配置eureka.client.service-url.defaultZone 属性 即可自动注册到 Eureka Server。

yaml 复制代码
spring.application.name=DEPARTMENT-SERVICE
eureka.instance.client.serviceUrl.defaultZone=http://localhost:8761/eureka/

运行部门服务Eureka客户端

完成此配置后,启动Department-service并访问 http://localhost:8761。 看到部门服务已使用 SERVICE ID 注册为 DEPARTMENT-SERVICE,注意到状态为 UP(1),这意味着服务已启动并正在运行,并且部门服务的一个实例正在运行。

将User-Service微服务注册为Eureka客户端

添加以下依赖

xml 复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

在application.properties中配置eureka.client.service-url.defaultZone 属性 即可自动注册到 Eureka Server。

yaml 复制代码
spring.application.name=USER-SERVICE
eureka.instance.client.serviceUrl.defaultZone=http://localhost:8761/eureka/

当服务注册到 Eureka Server 时,它会在一定的时间间隔内不断发送心跳。如果 Eureka 服务器没有收到来自任何服务实例的心跳,它将假定该服务实例已关闭并将其从池中取出

修改user-service的ApiClient

上一节中中,我们使用APIClient完成了进行服务调用,但是是写了部门服务的url

java 复制代码
@FeignClient(value = "DEPARTMENT-SERVICE", url = "http://localhost:8080")

这次我们修改如下,去除url属性

java 复制代码
@FeignClient(value = "DEPARTMENT-SERVICE")

完整api如下

java 复制代码
package io.wz.userservice.service;

import io.wz.userservice.dto.DepartmentDto;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(value = "DEPARTMENT-SERVICE")
public interface APIClient {
    @GetMapping(value = "/api/departments/{id}")
    DepartmentDto getDepartmentById(@PathVariable("id") String departmentId);
}

运行用户服务Eureka客户端

以上配置后,启动 user-service 并访问http://localhost:8761。看到user-service已使用 SERVICE ID 注册为USER-SERVICE。 您还可以注意到状态为 UP(1),这意味着服务已启动并正在运行,并且用户服务的一个实例正在运行。

测试

增加测试日志

在部门服务的DepartmentServiceImplgetDepartmentById方法增加调试日志,如果调用到此接口,会打印getDepartment By Id

java 复制代码
    @Override
    public Department getDepartmentById(Long departmentId) {
        log.info("getDepartment By Id:{} ",departmentId);
        return departmentRepository.findById(departmentId).get();
    }

启动2个Department-Service

1. 启动一个8082的部门服务

在idea中复制DepartmentServiceApplication配置,同时在启动参数指定应用端口 -Dserver.port=8082

2. 启动默认的部门服务,端口为8080

以上2个部门服务启动完成,会在eureka看到2个部门服务

点击获取用户 REST API进行测试

多点击几次,会看到2个部门服务控制台都会打印,getDepartment By Id:1,这里使用的是Spring Cloud LoadBalancer提供的轮训算法

结论

在本教程中,我们学习了如何在 Spring boot 微服务项目中使用Eureka来进行服务的注册与发现,同时基于Feign进行服务的调用,但是这里还有遗留问题,如

  • 启动服务以后需要多久才会被消费方查询到地址?
  • 如果要做服务更新,如何让消费无感知,感受不到服务再重启?
  • 如何让调用方知道调用的是提供方多个实例中具体哪一个服务实例?

以上问题后续文章解答,请关注此公众号。

源码下载: github gitee

相关推荐
seventeennnnn19 分钟前
谢飞机的Java高级开发面试:从Spring Boot到分布式架构的蜕变之旅
spring boot·微服务架构·java面试·分布式系统·电商支付
超级小忍2 小时前
服务端向客户端主动推送数据的几种方法(Spring Boot 环境)
java·spring boot·后端
时间会给答案scidag2 小时前
报错 400 和405解决方案
vue.js·spring boot
Wyc724093 小时前
SpringBoot
java·spring boot·spring
ladymorgana4 小时前
【Spring Boot】HikariCP 连接池 YAML 配置详解
spring boot·后端·mysql·连接池·hikaricp
Code季风5 小时前
Gin Web 层集成 Viper 配置文件和 Zap 日志文件指南(下)
前端·微服务·架构·go·gin
Code季风5 小时前
Gin Web 服务集成 Consul:从服务注册到服务发现实践指南(下)
java·前端·微服务·架构·go·gin·consul
GJCTYU6 小时前
spring中@Transactional注解和事务的实战理解附代码
数据库·spring boot·后端·spring·oracle·mybatis
风象南7 小时前
SpringBoot敏感配置项加密与解密实战
java·spring boot·后端
写不出来就跑路8 小时前
暑期实习感悟与经验分享:从校园到职场的成长之路
java·开发语言·经验分享·spring boot