一、Spring Cloud
1. 服务注册中心
常见的服务注册中心组件如下
- Eureka
- Consul
- Zookeeper
- Etcd
- Nacos
2. Eureka
SpringCloud 封装了 Netflix 公司开发的 Eureka 模块来实现服务治理。
什么是服务治理:在传统的 RPC 远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务于服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。
Eureka 采用了 CS 的设计架构,Eureka Sever 作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用 Eureka 的客户端连接到 Eureka Server 并维持心跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行。
在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息比如服务地址通讯地址等以别名方式注册到注册中心上。另一方(消费者服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地 RPC 调用。RPC 远程调用框架核心设计思想:在于注册中心,因为使用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)。在任何 RPC 远程框架中,都会有一个注册中心存放服务地址相关信息(接口地址)。
Eureka 采用 CS(Client/Server,客户端/服务器) 架构,它包括以下两大组件:
- Eureka Server:Eureka 服务注册中心,主要用于提供服务注册功能。当微服务启动时,会将自己的服务信息注册到 Eureka Server。Eureka Server 维护了一个可用服务列表,存储了所有注册到 Eureka Server 的可用服务节点的信息,服务节点的信息可以在 Eureka Server 的管理界面中直观看到。
- Eureka Client:Eureka 客户端,通常指的是微服务系统中各个微服务,主要用于和 Eureka Server 进行交互。在微服务应用启动后,Eureka Client 会向 Eureka Server 发送心跳(默认周期为 30 秒)。若 Eureka Server 在多个心跳周期内没有接收到某个 Eureka Client 的心跳,Eureka Server 将它从可用服务列表中移除(默认 90 秒)。
默认情况下,Eureka Server 同时也是 Eureka Client。多个 Eureka Server 实例,互相之间通过增量复制的方式,来实现服务注册表中数据的同步。Eureka Server 默认保证在 90 秒内,Eureka Server 集群内的所有实例中的数据达到一致。从这个架构来看,Eureka Server 所有实例所处的角色都是对等的,没有类似 Zookeeper、Consul、Etcd 等注册中心的选举过程,也不存在主从,所有的节点都是主节点。Eureka 官方将 Eureka Server 集群中的所有实例称为 “对等体”。
Eureka Client 会缓存服务注册表中的信息。这种方式有一定的优势——首先,微服务无需每次请求都查询 Eureka Server,从而降低了 Eureka Server 的压力;其次,即使 Eureka Server 所有节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者并完成调用。
2.1 服务注册与发现的流程
Eureka 实现服务注册与发现的流程如下:
1. 搭建一个 Eureka Server 作为服务注册中心;
2. 服务提供者 Eureka Client 启动时,会把当前服务器的信息以服务名(spring.application.name)的方式注册到服务注册中心;
3. 服务消费者 Eureka Client 启动时,也会向服务注册中心注册;
4. 服务消费者还会获取一份可用服务列表,该列表中包含了所有注册到服务注册中心的服务信息(包括服务提供者和自身的信息);
5. 在获得了可用服务列表后,服务消费者通过 `HTTP` 或消息中间件远程调用服务提供者提供的服务。
2.2 环境配置
1. 创建 Spring Initializr 项目
<?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.6.10</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.gupaoedu</groupId>
<artifactId>eureka_demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka_demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2021.0.3</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>
</plugin>
</plugins>
</build>
</project>
2. 添加 @EnableEurekaServer 注解;
package com.gupaoedu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EurekaDemoApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaDemoApplication.class, args);
}
}
3. 启动服务;
4. 解决报错问题,application.properties 添加如下配置
# Eureka Server 默认端口地址
server.port=8761
# Eureka Server 默认注册地址
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
5. 不注册自己
# 应用名称,应用名称会在Eureka中作为服务名称
spring.application.name=spring-cloud-eureka-server
# Eureka Server 默认端口地址
server.port=8761
# Eureka Server 默认注册地址
#eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
# 当前自己就是server,不需要注册自己
eureka.client.register-with-eureka=false
# 查询获取注册中心的服务信息,自己就是Server,所以不需要获取
eureka.client.fetch-registry=false
2.3 服务提供者实现注册
1. 新建一个 spring-cloud-product-service 的 Spring Initializr 项目;
- 添加 Web --> Spring Web 依赖
- 添加 Spring Cloud Discovery --> Eureka Discovery Client 依赖
<?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.6.10</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.gupaoedu</groupId>
<artifactId>spring-cloud-product-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-cloud-product-service</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2021.0.3</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-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>
2. 新建 ProductController.java 文件
package com.gupaoedu.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ProductController {
@GetMapping("/product/{id}")
public String findById(@PathVariable("id") Integer id) {
return "Success";
}
}
3. 配置 application.properties 文件;
spring.application.name=spring-cloud-product-service
server.port=8080
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
4. 运行。
2.4 服务消费者的远程调用
1. 新建一个 spring-cloud-user-service 的 Spring Initializr 项目;
- 添加 Web --> Spring Web 依赖
- 添加 Spring Cloud Discovery --> Eureka Discovery Client 依赖
<?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.1.14.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.gupaoedu</groupId>
<artifactId>spring-cloud-user-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-cloud-user-service</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR6</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-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>
2. 新建 TestController;
package com.gupaoedu.controller;
import com.netflix.discovery.converters.Auto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class TestController {
@Autowired
RestTemplate restTemplate;
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
@GetMapping("/product/{id}")
public String queryProductInfo(@PathVariable("id")int id){
return restTemplate.getForObject("http://product-service/product/"+id, String.class);
}
}
3. 配置 application.properties 文件;
spring.application.name=user-service
server.port=8081
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
2.5 Eureka Server 的高可用
1. 新建一个 spring-cloud-eureka-server-replicate 的 Spring Initializr 项目;
- 添加 Spring Cloud Discovery --> Eureka Server 依赖
<?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.6.10</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.gupaoedu</groupId>
<artifactId>spring-cloud-eureka-replica</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-cloud-eureka-replica</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2021.0.3</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>
</plugin>
</plugins>
</build>
</project>
2. 相互注册;
- 项目 spring-cloud-eureka-replica 的 Eureka 注册地址指向 8761 端口
spring.application.name=spring-cloud-eureka-replica
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
server.port=8762
- 项目 eureka_demo 的 Eureka 注册地址指向 8762 端口
# 应用名称,应用名称会在Eureka中作为服务名称
spring.application.name=spring-cloud-eureka-server
# Eureka Server 默认端口地址
server.port=8761
# Eureka Server 默认注册地址
eureka.client.service-url.defaultZone=http://localhost:8762/eureka/
# 当前自己就是server,不需要注册自己
eureka.client.register-with-eureka=false
# 查询获取注册中心的服务信息,自己就是Server,所以不需要获取
eureka.client.fetch-registry=false
3. 高可用配置
- 项目 eureka_demo 配置 application.properties
# 应用名称,应用名称会在Eureka中作为服务名称
spring.application.name=spring-cloud-eureka-server
# Eureka Server 默认端口地址
server.port=8761
eureka.instance.hostname=eureka1
# Eureka Server 默认注册地址
eureka.client.service-url.defaultZone=http://eureka2:8762/eureka/
# 当前自己就是server,不需要注册自己
eureka.client.register-with-eureka=false
# 查询获取注册中心的服务信息,自己就是Server,所以不需要获取
eureka.client.fetch-registry=false
- 项目 spring-cloud-eureka-replica 配置 application.properties
spring.application.name=spring-cloud-eureka-replica
server.port=8762
eureka.instance.hostname=eureka2
eureka.client.service-url.defaultZone=http://eureka1:8761/eureka
- 项目 spring-cloud-product-service 配置 application.properties
spring.application.name=spring-cloud-product-service
server.port=8080
eureka.client.service-url.defaultZone=http://localhost:8761/eureka,http://localhost:8762/eureka
- 项目 spring-cloud-user-service 配置 application.properties
spring.application.name=spring-cloud-user-service
server.port=8081
eureka.client.service-url.defaultZone=http://localhost:8761/eureka,http://localhost:8762/eureka
2.6 自我保护机制
Eureka 服务端会检查最近 15 分钟内所有 Eureka 实例正常心跳占比,如果低于 85% 就会触发自我保护机制。触发了保护机制,Eureka 将暂时把这些失效的服务保护起来,不让其过期,但这些服务也并不是永远不会过期。Eureka 在启动完成后,每隔 60 秒会检查一次服务健康状态,如果这些被保护起来失效的服务过一段时间后(默认 90 秒)还是没有恢复,就会把这些服务剔除。如果在此期间服务恢复了并且实例心跳占比高于 85%时,就会自动关闭自我保护机制。
为什么会有自我保护机制?
Eureka 服务端为了防止 Eureka 客户端本身是可以正常访问的,但是由于网路通信故障等原因,造成 Eureka 服务端失去于客户端的连接,从而形成的不可用。因为网络通信是可能恢复的,但是 Eureka 客户端只会在启动时才去服务端注册。如果因为网络的原因而剔除了客户端,将造成客户端无法再注册到服务端。
3. Ribbon
3.1 创建注册中心
1. 创建一个 eureka-service 的 Spring Initializr 项目;
- 添加 Web --> Spring Web 依赖
- 添加 Spring Cloud Discovery --> Eureka Server 依赖
配置 eureka.server.enable-self-preservation = false 关闭自我保护机制。
<?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.6.10</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.gupaoedu</groupId>
<artifactId>eureka-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka-service</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2021.0.3</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-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>
</plugin>
</plugins>
</build>
</project>
2. 开启 @EnableEurekaServer 注解
package com.gupaoedu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EurekaServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServiceApplication.class, args);
}
}
3. 配置 application.properties;
server.port=8761
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
4. 启动工程。
3.2 创建服务提供者
1. 创建一个 provider-service 的 Spring Initializr 项目;
- 添加 Web --> Spring Web 依赖
- 添加 Spring Cloud Discovery --> Eureka Discovery Client 依赖
<?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.6.10</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.gupaoedu</groupId>
<artifactId>provider-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>provider-service</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2021.0.3</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-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>
2. 创建 HelloController.java
package com.gupaoedu.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("hello")
public String Hello() {
System.out.println("接收到请求");
return "Hello ......";
}
}
3. 修改 application.properties 配置文件
spring.application.name=provider-service
server.port=8080
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
4. Edit Configurations
5. 启动 ProviderService-01 和 ProviderService-02 。
3.3 创建服务消费者
1. 创建一个 consumer-service 的 Spring Initializr 项目;
- 添加 Web --> Spring Web 依赖
- 添加 Spring Cloud Discovery --> Eureka Discovery Client 依赖
<?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.1.14.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.gupaoedu</groupId>
<artifactId>consumer-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>consumer-service</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR6</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-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>
2. 创建 TestContrlller ;
package com.gupaoedu.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class TestContrlller {
@Autowired
RestTemplate restTemplate;
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@GetMapping("/test")
public String test() {
return restTemplate.getForObject("http://provider-service/hello", String.class);
}
}
3. 修改 application.properties 配置文件;
spring.application.name=consumer-service
server.port=8083
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
4. OpenFeign
1. 基于 consumer-service 项目,修改 pom.xml 文件;
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<?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.6.10</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.gupaoedu</groupId>
<artifactId>consumer-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>provider-service</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2021.0.3</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>
</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>
2. 创建 IHelloControllerFeign 接口
package com.gupaoedu.controller;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient("provider-service")
public interface IHelloControllerFeign {
@GetMapping("hello")
String Hello();
}
3. ConsumerServiceApplication 开启 @EnableFeignClients;
package com.gupaoedu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients
@SpringBootApplication
public class ConsumerServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerServiceApplication.class, args);
}
}
4. 新建 TestHelloController;
package com.gupaoedu.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestHelloController {
@Autowired
IHelloControllerFeign helloControllerFeign;
@GetMapping("/hello")
public String test() {
return helloControllerFeign.Hello();
}
}
5. Spring Cloud Gateway
Spring Cloud Gateway 底层使用了高性能的通信框架 Netty。
5.1 SpringCloud Gateway 特征
SpringCloud 官方,对 SpringCloud Gateway 特征介绍如下:
(1)基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0。
(2)集成 Hystrix 断路器。
(3)集成 Spring Cloud DiscoveryClient。
(4)Predicates 和 Filters 作用于特定路由,易于编写的 Predicates 和 Filters。
(5)具备一些网关的高级功能:动态路由、限流、路径重写。
从以上的特征来说,和 Zuul 的特征差别不大。SpringCloud Gateway 和 Zuul 主要的区别,还是在底层的通信框架上。
简单说明一下上文中的三个术语:
(1)Filter(过滤器):
和 Zuul 的过滤器在概念上类似,可以使用它拦截和修改请求,并且对上游的响应,进行二次处理。过滤器为 org.springframework.cloud.gateway.filter.GatewayFilter 类的实例。
(2)Route(路由):
网关配置的基本组成模块,和 Zuul 的路由配置模块类似。一个 Route 模块由一个 ID,一个目标 URI,一组断言和一组过滤器定义。如果断言为真,则路由匹配,目标 URI 会被访问。
(3)Predicate(断言):
这是一个 Java 8 的 Predicate,可以使用它来匹配来自 HTTP 请求的任何内容,例如 headers 或参数。断言的输入类型是一个 ServerWebExchange。
5.2 路由配置方式
如果请求的目标地址,是单个的 URI 资源路径,配置文件示例如下:
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
-id: url-proxy-1
uri: http://localhost:8088
predicates:
-Path=/gateway
各字段含义如下:
id:我们自定义的路由 ID,保持唯一
uri:目标服务地址
predicates:路由条件,Predicate 接受一个输入参数,返回一个布尔值结果。
该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非)。
上面这段配置的意思是,配置了一个 id 为 url-proxy-1 的 URI 代理规则,路由的规则为:
当访问地址 http://localhost:8080/gupao/1.jsp 时,会路由到上游地址 http://localhost:8088/1.jsp。
5.3 基于代码的路由配置方式
package com.gupaoedu.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("path_route", r -> r.path("/gateway")
.uri("http://localhost:8088"))
.build();
}
}
5.4 gateWay 的主要功能之一是转发请求
转发规则的定义主要包含三个部分
| | | |
| ----------------------- | ------------------------------------------------------------ | ---- |
| Route(路由) | 路由是网关的基本单元,由ID、URI、一组Predicate、一组Filter组成,根据Predicate进行匹配转发。 | |
| Predicate(谓语、断言) | 路由转发的判断条件,目前SpringCloud Gateway支持多种方式,常见如:Path、Query、Method、Header等,写法必须遵循 key=vlue的形式 | |
| Filter(过滤器) | 过滤器是路由转发请求时所经过的过滤逻辑,可用于修改请求、响应内容 | |
> 其中Route和Predicate必须同时申明。