本文详细介绍如何使用 Spring CloudEureka 实现一个微服务架构,包括服务中心集群、服务提供者集群以及服务消费者的实现。通过本例,您将学习到如何配置和使用Eureka进行服务注册与发现。具体的代码可以在github上看到:zhifengmuxue/springcloud-learn: 微服务架构学习 (github.com)

架构设计

我们将实现1个服务中心集群,1个服务提供者集群以及1个服务消费者的架构;通过服务中心Eureka来进行服务治理,服务消费者调用服务提供者的服务。我们的架构由以下几部分组成:

  • 服务中心集群(Eureka Server)
  • 服务提供者集群(Eureka Client)
  • 服务消费者(使用Feign进行调用)
framework

创建Spring Cloud 项目

创建一个springBoot项目

Pasted image 20241010193659

导入spring cloud 依赖以及 eureka 依赖(2018年停止维护,仅在这里用于简要说明spring cloud的工作原理,后续开发可以选用Consul或其他的实现服务集群)
附上依赖:

1
2
3
4
5
6
7
8
<dependency>  
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>

用Eureka实现“服务中心”

添加配置文件

我们需要配置“服务中心”的地址、端口号和应用名称等重要的信息

Pasted image 20241010194616
1
2
3
4
5
6
spring.application.name=eureka-server-demo   # 应用名称
server.port=8080 # 服务器端口号
eureka.client.register-with-eureka=true # 是否注册到Eureka Server
eureka.client.fetch-registry=true # 是否从Eureka Server获取注册信息
# 设置与Eureka Server交互的地址。查询服务和注册服务均依赖于此
eureka.client.serviceUrl.defaultZone=http://localhost:${server.port}/eureka/

实现“服务中心”集群

这一部分演示的是在一台电脑上实现“服务中心”集群,这里模拟三台:

访问URI IP(本机) 节点名称 端口号
http://node1:8081 127.0.0.1 node1 8081
http://node2:8082 127.0.0.1 node2 8082
http://node3:8083 127.0.0.1 node3 8083
配置虚拟地址

我们先去修改本机的DNS表,新增集群的域名转换,一般配置文件在 C:\\Windows\System32\drivers\etc 下,名为 hosts 的文件

多环境配置

接下来我们要创建多个配置文件,来模拟多个“服务中心”

Pasted image 20241010195845

创建节点node1的配置文件 application-node1.properties,并将“service-url”指向节点node2,node3

1
2
3
4
5
6
7
8
spring.application.name=eureka-server-demo  
server.port=8081
# 节点的名称
eureka.instance.hostname=node1
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
# 设置与Eureka Server交互的地址
eureka.client.service-url.defaultZone=http://node2:8082/eureka/,http://node3:8083/eureka/

同理,我们创建node2,node3的配置文件:

Pasted image 20241010200159

(这里的图的域名写的不正确,导致呈现效果不好,这里的代码块已经修改,用节点名更换localhost)

注意点1

要注意的是,配置完成后无法直接启动服务,我们需要在启动器上应用注解@EnableEurekaServer

1
2
3
4
5
6
7
8
9
@SpringBootApplication  
@EnableEurekaServer
public class EurekaServerDemoApplication {

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

}
Pasted image 20241010202359

启动之后访问8080端口即可看到服务:

Pasted image 20241010202447

注意点2

启动会抛出异常 Exception: java.net.ConnectException: Connection refused:
注意几个配置文件都要更改,因为后面要分别运行。

Pasted image 20241010202728

我们需要修改配置文件防止Eureka启动时注册本身服务。
参考:SpringCloud —— Eureka详细使用教程,以及实战案例演示-CSDN博客

打包和部署”服务中心“

使用maven工具进行打包,记得打包前先进行clean操作

Pasted image 20241010200729 Pasted image 20241010203052

接下来我们使用命令行启动这三个服务,在命令行进入jar包的目录下,执行:

1
2
3
java -jar eureka-server-demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=node1
java -jar eureka-server-demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=node2
java -jar eureka-server-demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=node3

要注意的是,需要开三个命令行,分别运行上面的语句,因为我们要模拟的是三台服务中心。

Pasted image 20241010204315

我们需要依次去访问路径看看服务是否成功。(这里我发现我的8082端口占用最后换用了9000-9002端口继续进行)

Pasted image 20241010205711

至此,多节点服务中心集群已经配置完成

用Eureka实现”服务提供者“

实现”服务提供者“的客户端

1. 创建Eureka客户端项目

导入eureka discovery client依赖以及springboot web依赖:

1
2
3
4
5
6
7
8
<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>
2. 添加配置
1
2
3
spring.application.name=eureka-provider-demo  
server.port=9005
eureka.client.service-url.defaultZone=http://node1:9000/eureka/,http://node2:9001/eureka/,http://node3:9002/eureka/

把之前的三个配置完成的服务中心集群的地址填入这里。

3. 启用注册和发现

在启动类中添加注解 @EnableDiscoveryClient

1
2
3
4
5
6
7
8
9
@SpringBootApplication  
@EnableDiscoveryClient
public class EurekaProviderDemoApplication {

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

}
4. 添加一个测试接口
1
2
3
4
5
6
7
8
9
10
11
12
13
@RestController  
public class HelloController {
@Value("${spring.application.name}")
private String applicationName;

@Value("${server.port}")
private String port;

@RequestMapping("/hello")
public String hello() {
return "Hello from " + applicationName + ":" + port;
}
}

检查服务的有效性

启动服务中心集群,启动服务提供者应用,进入控制台查看服务是否注册:

Pasted image 20241010212127

可以发现在 Instances currently registered with Eureka下出现了应用名称,但是上面出现了一行红字
” **EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.**“ 这是Eureka的心跳检测,在测试环境中我们可以使用配置将其关闭,但是上线时一定要保证开启:

1
eureka.server.enable-self-preservation=false

我们去访问服务提供者,可以发现能够正常访问,这说明”服务提供者“接口正在正常工作

Pasted image 20241010212519

实现”服务提供者“集群

我们修改接口,让他能够区分属于哪一个服务提供者:

1
2
3
4
5
6
7
8
9
10
11
12
13
@RestController  
public class HelloController {
@Value("${provider}")
private String name; // 改为服务提供者名字

@Value("${server.port}")
private String port;

@RequestMapping("/hello")
public String hello() {
return "Hello from " + name + ":" + port;
}
}

下面我们编写配置文件,然后如同“服务中心”集群一样操作

Pasted image 20241010213004

maven打包,在命令行中执行:

1
2
java -jar eureka-provider-demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=provider1
java -jar eureka-provider-demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=provider2

同样需要在两个窗口执行哦

Pasted image 20241010213630

至此,”服务提供者“集群配置完成

使用Feign实现”服务消费者“

实现”服务消费者“客户端

1. 创建Eureka客户端项目

导入 Eureka Discovery Client 依赖 springboot web依赖以及Feign客户端依赖

1
2
3
4
5
6
7
8
9
10
11
12
<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>
2. 添加配置
1
2
3
4
spring.application.name=eureka-custom-demo  
server.port=10005
eureka.client.register-with-eureka=false
eureka.client.service-url.defaultZone=http://node1:9000/eureka/,http://node2:9001/eureka/,http://node3:9002/eureka/

这里不需要把消费者注册到服务中心,设置为false

调用”服务提供者“接口

1. 启用客户端发现和远程调用

@EnableDiscoveryClient 注解启用客户端的服务注册和发现功能,@EnableFeignClients 注解启用Feign的远程服务调用。

1
2
3
4
5
6
7
8
@SpringBootApplication  
@EnableDiscoveryClient
@EnableFeignClients
public class EurekaCustomDemoApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaCustomDemoApplication.class, args);
}
}
2. 编写接口

定义一个接口,注解@FeignClient 中的 name 属性时远程”服务提供者“的名字,此接口中的方法需要和远程”服务提供者“中的方法名和参数保持一致

1
2
3
4
5
@FeignClient(name = "eureka-provider-demo")  
public interface MyFeignClient {
@RequestMapping("/hello")
String hello();
}
3. 实现客户端接口

接下来将实现的MyFeignClient接口注入Controller层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController  
public class ConsumerController {
private final MyFeignClient myFeignClient;

@Autowired
public ConsumerController(MyFeignClient myFeignClient) {
this.myFeignClient = myFeignClient;
}

@RequestMapping("/hello")
public String hello() {
return myFeignClient.hello();
}
}

这个接口将提供给最终用户

测试微服务系统

启动服务

启动”服务中心“集群,”服务提供者“集群,”服务消费者“

访问服务消费者

访问接口 http://localhost:10005/hello

Pasted image 20241010215946

返回的是服务provider1的服务,因为实现了”服务提供者“负载均衡,当你在此访问时,会出现:

Pasted image 20241010220055

多次访问,会交替出现上述两种情况,这说明”服务提供者“集群已经正常工作。

异常测试

可以尝试关闭其中任意一个”服务提供者“,在此访问接口,依旧能正常工作;
可以尝试关闭其中任意两个”服务中心“,在此访问接口,依旧能正常工作。