Springcloud基础知识(2)- Spring Cloud Eureka (一) | 服务注册与发现



Eureka 一词来源于古希腊词汇,是 “发现了” 的意思。在软件领域,Eureka 是 Netflix 公司开发的一款开源的服务注册与发现组件。

Spring Cloud 将 Eureka 与 Netflix 中的其他开源服务组件(例如 Ribbon、Feign 以及 Hystrix 等)一起整合进 Spring Cloud Netflix 模块中,整合后的组件全称为 Spring Cloud Netflix Eureka。

Eureka 是 Spring Cloud Netflix 模块的子模块,它是 Spring Cloud 对 Netflix Eureka 的二次封装,主要负责 Spring Cloud 的服务注册与发现功能。

Spring Cloud 使用 Spring Boot 思想为 Eureka 增加了自动化配置,开发人员只需要引入相关依赖和注解,就能将 Spring Boot 构建的微服务轻松地与 Eureka 进行整合。

Eureka 采用 CS(Client/Server,客户端/服务器) 架构,它包括以下两大组件:

    (1) Eureka Server:Eureka 服务注册中心,主要用于提供服务注册功能。当微服务启动时,会将自己的服务注册到 Eureka Server。Eureka Server 维护了一个可用服务列表,存储了所有注册到 Eureka Server 的可用服务的信息,这些可用服务可以在 Eureka Server 的管理界面中直观看到。
    (2) Eureka Client:Eureka 客户端,通常指的是微服务系统中各个微服务,主要用于和 Eureka Server 进行交互。在微服务应用启动后,Eureka Client 会向 Eureka Server 发送心跳(默认周期为 30 秒)。若 Eureka Server 在多个心跳周期内没有接收到某个 Eureka Client 的心跳,Eureka Server 将它从可用服务列表中移除(默认 90 秒)。

    注:“心跳” 指的是一段定时发送的自定义信息,让对方知道自己 “存活”,以确保连接的有效性。大部分 CS 架构的应用程序都采用了心跳机制,服务端和客户端都可以发心跳。通常情况下是客户端向服务器端发送心跳包,服务端用于判断客户端是否在线。

Eureka 服务注册与发现涉及到以下 3 个角色:
    
    (1) 服务注册中心(Register Service):它是一个 Eureka Server,用于提供服务注册和发现功能。
    (2) 服务提供者(Provider Service):它是一个 Eureka Client,用于提供服务。它将自己提供的服务注册到服务注册中心,以供服务消费者发现。
    (3) 服务消费者(Consumer Service):它是一个 Eureka Client,用于消费服务。它可以从服务注册中心获取服务列表,调用所需的服务。

Eureka 实现服务注册与发现的流程如下:

    (1) 搭建一个 Eureka Server 作为服务注册中心;
    (2) 服务提供者 Eureka Client 启动时,会把当前服务器的信息以服务名(spring.application.name)的方式注册到服务注册中心;
    (3) 服务消费者 Eureka Client 启动时,也会向服务注册中心注册;
    (4) 服务消费者还会获取一份可用服务列表,该列表中包含了所有注册到服务注册中心的服务信息(包括服务提供者和自身的信息);
    (5) 在获得了可用服务列表后,服务消费者通过 HTTP 或消息中间件远程调用服务提供者提供的服务。

服务注册中心(Eureka Server)所扮演的角色十分重要,它是服务提供者和服务消费者之间的桥梁。服务提供者只有将自己的服务注册到服务注册中心才可能被服务消费者调用,而服务消费者也只有通过服务注册中心获取可用服务列表后,才能调用所需的服务。


示例


在 “ ” 里的项目 SpringcloudDemo01 完成了 Maven 多模块 Spring Boot 项目。

本文将完全复制 SpringcloudDemo01 的代码和配置到新项目 SpringcloudDemo02,并在新项目 SpringcloudDemo02 的基础上修改代码和配置,来演示 Eureka 实现服务注册与发现。

1. 主项目 SpringcloudDemo02

    修改 pom.xml, 添加配置如下。

 1         <dependencyManagement>
 2             <dependencies>
 3 
 4                 
 7                 <dependency>
 8                     <groupId>org.springframework.cloudgroupId>
 9                     <artifactId>spring-cloud-dependenciesartifactId>
10                     
11                     <version>2021.0.3version>
12                     <type>pomtype>
13                     <scope>importscope>
14                 dependency>
15 
16             dependencies>
17         dependencyManagement>

    Spring Cloud 版本和 Spring Boot 版本对应关系:

Spring Cloud 版本 Spring Boot 版本
2022.0.0-M2 >= 3.0.0-M2 and < 3.1.0-M1
2022.0.0-M1 >= 3.0.0-M1 and < 3.0.0-M2
2021.0.3 >= 2.6.1 and < 3.0.0-M1
2021.0.0-x >= 2.6.0-M1 and < 2.6.1
2020.0.5 >= 2.4.0.M1 and < 2.6.0-M1
Hoxton.SR12 >= 2.2.0.RELEASE and < 2.4.0.M1

2. CommonAPI 模块(公共子模块)

    1) 修改 pom.xml, 添加配置如下。

1         <dependencies>
2             <dependency>
3                 <groupId>org.projectlombokgroupId>
4                 <artifactId>lombokartifactId>
5                 <version>1.18.8version>
6             dependency>
7         dependencies>


        lombok 提供了一些简化实体类定义的注解,常用的注解如下:

            @Getter 使用方法同上,区别在于生成的是 getter 方法。
            @Setter 注解在类或字段,注解在类时为所有字段生成 setter 方法,注解在字段上时只为该字段生成setter 方法。
            @ToString 注解在类,添加 toString 方法。
            @NoArgsConstructor 注解在类,生成无参的构造方法。
            @AllArgsConstructor 注解在类,生成包含类中所有字段的构造方法。
            @RequiredArgsConstructor 注解在类,为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段。
            @EqualsAndHashCode 注解在类,生成 hashCode 和 equals 方法。
            @Data 注解在类,生成 setter/getter、equals、canEqual、hashCode、toString 方法,如为 final 属性,则不会为该属性生成 setter 方法。
            @Slf4j 注解在类,生成 log 变量,严格意义来说是常量。

        IDEA 还需要安装 lombok 插件,这里以 Windows 版的 IDEA 为例,安装步骤如下:

            菜单 File -> Settings -> 选中左侧 Plugin ->  搜索 "lombok" -> Install lombok plugin -> Restart IDEA


    2) 创建 src/main/java/com/example/entity/Employee.java 文件

 1         package com.example.entity;
 2 
 3         import lombok.Data;
 4         import lombok.NoArgsConstructor;
 5         import lombok.experimental.Accessors;
 6         import java.io.Serializable;
 7 
 8         @NoArgsConstructor // 无参构造函数
 9         @Data // 提供类的 get、set、equals、hashCode、canEqual、toString 方法
10         @Accessors(chain = true)
11         public class Employee implements Serializable {
12             private Integer id;
13             private String name;
14             private Integer port;
15 
16         }


    3) 安装 CommonAPI 到本地 Maven 仓库

        View -> Tool Windows -> Maven -> SpringcloudDemo02 -> Lifecycle -> install

        查看本地仓库,SpringcloudDemo02 和 CommonAPI 包被安装好了。

        注:CommonAPI 依赖于 SpringcloudDemo02 的 pom 包,所以需要同时安装 SpringcloudDemo02 的 pom 包。由于被设置了 属性,RegisterServer 模块和 ServiceProvider 模块不会被安装。
        
        另外,SpringcloudDemo02 是复制 SpringcloudDemo01 项目而来的,如果之前安装过 SpringcloudDemo01,先把本地仓库里 SpringcloudDemo01 的相关包删除。


3. RegisterServer 模块(服务注册中心)

    1) 修改 pom.xml,添加配置如下

 1         <dependencies>
 2             <dependency>
 3                 <groupId>org.springframework.bootgroupId>
 4                 <artifactId>spring-boot-starter-webartifactId>
 5             dependency>
 6             <dependency>
 7                 <groupId>org.springframework.bootgroupId>
 8                 <artifactId>spring-boot-starter-testartifactId>
 9                 <scope>testscope>
10             dependency>
11             
12             <dependency>
13                 <groupId>org.springframework.cloudgroupId>
14                 <artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
15             dependency>
16         dependencies>
17 
18         <build>
19             <plugins>
20                 <plugin>
21                     <groupId>org.springframework.bootgroupId>
22                     <artifactId>spring-boot-maven-pluginartifactId>
23                     <configuration>
24                         <mainClass>com.example.AppmainClass>
25                         <layout>JARlayout>
26                     configuration>
27                     <executions>
28                     <execution>
29                         <goals>
30                         <goal>repackagegoal>
31                         goals>
32                     execution>
33                     executions>
34                 plugin>
35             plugins>
36         build>


        在IDE中项目列表 -> SpringcloudDemo02 -> 点击鼠标右键 -> Maven -> Reload Project


    2) 创建 src/main/resources/application.yml 文件

 1         server:
 2             port: 7001  # 端口号
 3         eureka:
 4             instance:
 5                 hostname: localhost # eureka 主机名
 6             client:
 7                 register-with-eureka: false # false 表示不向注册中心注册自己。
 8                 fetch-registry: false # false 表示就是注册中心,不需要去检索服务
 9                 service-url:
10                     defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ # 单机版服务注册中心

    3) 修改 src/main/java/com/example/App.java 文件

 1         package com.example;
 2 
 3         import org.springframework.boot.SpringApplication;
 4         import org.springframework.boot.autoconfigure.SpringBootApplication;
 5         import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
 6 
 7         @SpringBootApplication
 8         @EnableEurekaServer // 开启 Eureka server,接受其它微服务的注册
 9         public class App {
10             public static void main(String[] args) {
11                 SpringApplication.run(App.class, args);
12             }
13         }


    4) 打包运行

        菜单 Run -> Edit Configurations (或工具条上选择) —> 进入 Run/Debug Configurations 页面 -> Click "+" add new configuration -> Select "Maven":

            Working directory: RegisterServer 所在路径
            Command line: clean package

        -> Apply / OK

        Click Run "RegisterServer [clean, package]" ,jar 包生成在目录 target/ 里

            RegisterServer-1.0-SNAPSHOT.jar
            RegisterServer-1.0-SNAPSHOT.jar.original  

        打开 cmd 命令行窗口,进入 RegisterServer 模块目录,运行以下命令:

            java -jar target\RegisterServer-1.0-SNAPSHOT.jar

        浏览器访问 http://localhost:7001/,显示 Eureka 服务注册中心主页。


4. ServiceProvider 模块(服务提供者)

    1) 修改 pom.xml,添加配置如下

 1         <dependencies>
 2             <dependency>
 3                 <groupId>org.springframework.bootgroupId>
 4                 <artifactId>spring-boot-starter-webartifactId>
 5             dependency>
 6             <dependency>
 7                 <groupId>org.springframework.bootgroupId>
 8                 <artifactId>spring-boot-starter-testartifactId>
 9                 <scope>testscope>
10             dependency>
11             <dependency>
12                 <groupId>org.projectlombokgroupId>
13                 <artifactId>lombokartifactId>
14                 <version>1.18.8version>
15             dependency>            
16             
17             <dependency>
18                 <groupId>com.examplegroupId>
19                 <artifactId>CommonAPIartifactId>
20                 <version>${project.version}version>
21             dependency>         
22             
23             <dependency>
24                 <groupId>ch.qos.logbackgroupId>
25                 <artifactId>logback-coreartifactId>
26             dependency>
27             
28             <dependency>
29                 <groupId>org.springframeworkgroupId>
30                 <artifactId>springloadedartifactId>
31                 <version>1.2.8.RELEASEversion>
32             dependency>
33             
34             <dependency>
35                 <groupId>org.springframework.cloudgroupId>
36                 <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
37             dependency>
38         dependencies>
39 
40         <build>
41             <plugins>
42                 <plugin>
43                     <groupId>org.springframework.bootgroupId>
44                     <artifactId>spring-boot-maven-pluginartifactId>
45                     <configuration>
46                         <mainClass>com.example.AppmainClass>
47                         <layout>JARlayout>
48                     configuration>
49                     <executions>
50                     <execution>
51                         <goals>
52                         <goal>repackagegoal>
53                         goals>
54                     execution>
55                     executions>
56                 plugin>
57             plugins>
58         build>

    2) 创建 src/main/resources/application.yml 文件

 1         server:
 2             port: 8001      # 服务端口号
 3         spring:
 4             application:
 5                 name: employee-service-provider   # 微服务名称
 6 
 7         #### Eureka Client ####
 8         eureka:
 9             client:       # 将客户端注册到 eureka 服务列表内
10                 service-url:
11                     defaultZone: http://localhost:7001/eureka  # 服务注册中心地址
12 
13             instance:
14                 instance-id: sevice-provider-8001   # 自定义服务名称信息
15                 prefer-ip-address: true             # 显示访问路径的 ip 地址
16  

    3) 创建 src/main/java/com/example/controller/EmployeeController.java 文件

 1         package com.example.controller;
 2 
 3         import java.util.List;
 4         import java.util.ArrayList;
 5 
 6         import javax.servlet.http.HttpServletRequest;
 7 
 8         import lombok.extern.slf4j.Slf4j;
 9         import org.springframework.web.bind.annotation.RestController;
10         import org.springframework.web.bind.annotation.RequestMapping;
11         import org.springframework.web.bind.annotation.RequestMethod;
12         import org.springframework.web.bind.annotation.PathVariable;
13 
14         import com.example.entity.Employee;
15 
16         @RestController
17         @Slf4j
18         @RequestMapping(value = "/employee")
19         public class EmployeeController {
20 
21             @RequestMapping(value = "/list", method = RequestMethod.GET)
22             public List list(HttpServletRequest request) {
23 
24                 List employeeList = new ArrayList();
25 
26                 Employee e1 = new Employee();
27                 e1.setId(1);
28                 e1.setName("Test Name1");
29                 e1.setPort(request.getServerPort());
30                 employeeList.add(e1);
31 
32                 Employee e2 = new Employee();
33                 e2.setId(2);
34                 e2.setName("Test Name2");
35                 e2.setPort(request.getServerPort());
36                 employeeList.add(e2);
37 
38                 return employeeList;
39             }
40 
41             @RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
42             public Employee get(HttpServletRequest request, @PathVariable("id") int id) {
43 
44                 Employee e = new Employee();
45                 e.setId(id);
46                 e.setName("Employee " + id);
47                 e.setPort(request.getServerPort());
48                 return e;
49             }
50 
51         }

        注:Employee 实体类的 setter 是 lombok 的 @Data 注解生成的。

    4) 修改 src/main/java/com/example/App.java 文件

 1         package com.example;
 2 
 3         import org.springframework.boot.SpringApplication;
 4         import org.springframework.boot.autoconfigure.SpringBootApplication;
 5         import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
 6 
 7         @SpringBootApplication
 8         @EnableEurekaClient // 开启 Eureka client,自动注册到 Eureka Server 注册中心
 9         public class App {
10             public static void main(String[] args) {
11                 SpringApplication.run(App.class, args);
12             }
13         }


    5) 打包运行

        菜单 Run -> Edit Configurations (或工具条上选择) —> 进入 Run/Debug Configurations 页面 -> Click "+" add new configuration -> Select "Maven":

            Working directory: ServiceProvider 所在路径
            Command line: clean package

        -> Apply / OK

        Click Run "ServiceProvider [clean, package]" ,jar 包生成在目录 target/ 里

            ServiceProvider-1.0-SNAPSHOT.jar
            ServiceProvider-1.0-SNAPSHOT.jar.original  

        打开 cmd 命令行窗口,进入 ServiceProvider 模块目录,运行以下命令:

            java -jar target\ServiceProvider-1.0-SNAPSHOT.jar
       
        浏览器访问 http://localhost:8001/employee/list or  http://localhost:8001/employee/get/3。
        
        查看 http://localhost:7001/ 页面,显示如下:

            Instances currently registered with Eureka


            Application                                    AMIs      Availability Zones    Status
            EMPLOYEE-SERVICE-PROVIDER    n/a (1)        (1)                  UP (1) - sevice-provider-8001