# 从浅入深 学习 SpringCloud 微服务架构(十一)--SpringCloudGateWay(1)

本文主要是介绍# 从浅入深 学习 SpringCloud 微服务架构(十一)--SpringCloudGateWay(1),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

从浅入深 学习 SpringCloud 微服务架构(十一)–SpringCloudGateWay(1)

一、SpringCloudGateway:概述

1、Zuul 网关存在的问题

1.1 Zuul 中,整个请求的过程

首先将请求给 zuulservlet 处理,zuulservlet 中有一个 zuulRunner 对象,该对象中初始化了 Requestcontext: 作为存储整个请求的一些数据,并被所有的 zuulfilter 共享。

zuulRunner 中还有 FilterProcessor, FilterProcessor 作为执行所有的 zuulfilter 的管理器。

FilterProcessor 从 filterloader 中获取 zuulfilter,而 zuulfilter 是被 filterFileManager 所加载,并支持 groovy 热加载,采用了轮询的方式热加载。

有了这些 filter 之后,zuulservelet 首先执行的 Pre 类型的过滤器,再执行 route 类型的过滤器,最后执行的是 post 类型的过滤器。

如果在执行这些过滤器有错误的时候则会执行 error 类型的过滤器。执行完这些过滤器,最终将请求的结果返回给客户端。

1.2 在实际使用中我们会发现直接使用 Zuul 会存在诸多问题,包括:
  • 性能问题

Zuul1x 版本本质上就是一个同步 Servlet,采用多线程阻塞模型进行请求转发。

简单讲,每来一个请求,Servlet 容器要为该请求分配一个线程专门负责处理这个请求,直到响应返回客户端这个线程才会被释放返回容器线程池。

如果后台服务调用比较耗时,那么这个线程就会被阻塞,阻塞期间线程资源被占用,不能干其它事情。

我们知道 Servlet 容器线程池的大小是有限制的,当前端请求量大,而后台慢服务比较多时,很容易耗尽容器线程池内的线程,造成容器无法接受新的请求。

  • 不支持任何长连接,如 webspcket。

2、Zuul 网关的替换方案

  • Zuul2.x版本
  • SpringCloud Gateway

3、微服务网关 GateWay

Zuul 1.x 是一个基于阻塞 IO 的 APIGateway 以及 Servlet;
直到 2018年5月, u1 2.x(基于Netty,也是非阻塞的,支持长连接)才发布,但 Spring Cloud 暂时还没有整合计划。
Spring Cloud Gateway 比 Zuul1.x 系列的性能和功能整体要好。

3.1 Gateway 简介

Spring Cloud Gateway.是 Spring 官方基于 Spring5.0, Spring Boot 2.0 和 Project Reactor 等技术开发的网关,
旨在为微服务架构提供一种简单而有效的统一的 API 路由管理方式,统一访问接口。

SpringCloud Gateway 作为 Spring Cloud 生态系中的网关,目标是替代 NetflixZUUL,
其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,
例如:安全,监控/埋点,和限流等。它是基于Nttey的响应式开发模式。

3.2 Spring Cloud Gateway 与Zuul 的性能对比
组件RPS(request per second)
Spring Cloud GatewayRequests/sec: 32213.38
Zuu11XRequests/sec: 20800.13

从结果可知,Spring Cloud Gateway 的 RPS 是 Zuul 的 1.6 倍。

3.3 springcloud gateway 网关 功能模块
  • 路由配置
  • 过滤器
  • 统-鉴权
  • 网关限流
  • 网关的高可用

二、SpringCloudGateway 路由:基本配置

1、前言:SpringCloudGateway 路由 核心概念:

1.1 路由(route) :

路由是网关最基础的部分,路由信息由一个 ID、一个目的 URL、一组断言工厂和一组 Filter 组成。如果断言为真,则说明请求 URL 和配置的路由匹配。

1.2 断言(predicates):

java8 中的断言函数,Spring Cloud Gateway 中的断言函数输入类型是 Spring5.0 框架中的 ServerWebExchange。Spring Cloud Gateway 中的断言函数允许开发者去定义匹配来自 Http Request 中的任何信息,比如请求头和参数等。

1.3 过滤器(filter ):

一个标准的 Spring webFilter,Spring Cloud Gateway 中的 Filter 分为两种类型,分别是 Gateway Filter 和 Global Filter。过滤器 Filter 可以对请求和响应进行处理。

2、SpringCloudGateWay 网关:入门案例

1)创建工程,导入依赖坐标。
2)配置启动类
3)编写配置文件

2.1 SpringCloudGateWay 网关:入门案例–搭建环境,准备数据库。

— 创建数据库:
create database shop;

— 使用数据库:
use shop;

— 创建数据表:

	CREATE TABLE `tb_product` (`id` int NOT NULL AUTO_INCREMENT,`product_name` varchar(40) DEFAULT NULL COMMENT '名称',`status` int DEFAULT NULL COMMENT '状态',`price` decimal(10,2) DEFAULT NULL COMMENT '单价',`product_desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '描述',`caption` varchar(255) DEFAULT NULL COMMENT '标题',`inventory` int DEFAULT NULL COMMENT '库存',PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb3

— 插入数据:

insert into `tb_product` (`id`, `product_name`, `status`, `price`, `product_desc`, `caption`, `inventory`) values('1','iPhone 15 Pro','1','7999.00','iPhone 15 Pro 6.7 英寸或 6.1 英寸, 超视网膜 XDR 显示屏,ProMotion 自适应刷新率技术,钛金属搭配亚光质感玻璃背板, 灵动岛功能, A17 Pro 芯片,配备 6 核图形处理器, Pro 级摄像头系统,主摄 4800 万像素 | 超广角 | 长焦, 10 倍, 支持 USB 3, 视频播放最长可达 29 小时。 ','iPhone 15 Pro 巅峰之作','99');
2.2 SpringCloudGateWay 网关:入门案例–搭建环境–打开 idea 创建父工程

创建 artifactId 名为 spring_cloud_demo 的 maven 工程。

--> idea --> File --> New --> Project --> Maven Project SDK: ( 1.8(java version "1.8.0_131" ) --> Next --> Groupld : ( djh.it )Artifactld : ( spring_cloud_demo )Version : 1.0-SNAPSHOT--> Name: ( spring_cloud_demo )Location: ( ...\spring_cloud_demo\ )	--> Finish
2.3 SpringCloudGateWay 网关:入门案例–搭建环境–在父工程 spring_cloud_demo 的 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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>djh.it</groupId><artifactId>spring_cloud_demo</artifactId><packaging>pom</packaging><version>1.0-SNAPSHOT</version><modules><module>product_service</module><module>order_service</module><module>eureka_service</module><module>import_eurekaserver_test</module><module>api_zuul_service</module></modules><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.6.RELEASE</version></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.4</version><scope>provided</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Greenwich.RELEASE</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><repositories><repository><id>spring-snapshots</id><name>Spring Snapshots</name><url>http://repo.spring.io/libs-snapshot-local</url><snapshots><enabled>true</enabled></snapshots></repository><repository><id>spring-milestones</id><name>Spring Milestones</name><url>http://repo.spring.io/libs-milestone-local</url><snapshots><enabled>false</enabled></snapshots></repository><repository><id>spring-releases</id><name>Spring Releases</name><url>http://repo.spring.io/libs-release-local</url><snapshots><enabled>false</enabled></snapshots></repository></repositories><pluginRepositories><pluginRepository><id>spring-snapshots</id><name>Spring Snapshots</name><url>http://repo.spring.io/libs-snapshot-local</url><snapshots><enabled>true</enabled></snapshots></pluginRepository><pluginRepository><id>spring-milestones</id><name>Spring Milestones</name><url>http://repo.spring.io/libs-milestone-local</url><snapshots><enabled>false</enabled></snapshots></pluginRepository></pluginRepositories><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
<!-- spring_cloud_demo\pom.xml -->

3、SpringCloudGateWay 网关:入门案例–搭建环境–在父工程 spring_cloud_demo 下,创建子工程 eureka_service (子模块)。

3.1 创建 eureka_service 子工程(子模块)
	--> 右键 spring_cloud_demo 父工程--> Modules --> Maven --> Groupld : ( djh.it )Artifactld : ( eureka_service )Version : 1.0-SNAPSHOT--> Next --> Module name: ( eureka_service )Content root : ( \spring_cloud_demo\eureka_service )Module file location: ( \spring_cloud_demo\eureka_service )--> Finish
3.2 在子工程 eureka_service (子模块)中的 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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>spring_cloud_demo</artifactId><groupId>djh.it</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>eureka_service</artifactId><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency></dependencies></project>
<!-- spring_cloud_demo\eureka_service\pom.xml -->
3.3 在子工程 eureka_service (子模块)中,创建配置文件 application.yml 配置文件。
## spring_cloud_demo\eureka_service\src\main\resources\application.ymlserver:port: 9000  # 启动端口 命令行注入。spring:application:name: service-eureka  #spring应用名, # 注意 FeignClient 不支持名字带下划线eureka: # 配置 eureka_server
#  instance:
#    hostname: localhostclient:register-with-eureka: false  # 是否将自己注册到注册中心,不配置时,默认 true。 配置高可用时,须注销此行,或配置为 truefetch-registry: false  # 是否从 Eureka 中获取注册信息,不配置时,默认 true。 配置高可用时,须注销此行,或配置为 trueservice-url: # 配置暴露给 EurekaClient 的请求地址defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
3.4 在子工程 eureka_service (子模块)中,创建 启动类 EurekaServerApplication.java
/***   spring_cloud_demo\eureka_service\src\main\java\djh\it\eureka\EurekaServerApplication.java**   2024-4-19  启动类 EurekaServerApplication.java*/
package djh.it.eureka;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@SpringBootApplication
@EnableEurekaServer  //激活 Eureka
public class EurekaServerApplication {//运行启动类,浏览器地址栏输入:localhost:9000  进行访问测试。public static void main(String[] args) {SpringApplication.run(EurekaServerApplication.class, args);}
}
3.5 在子工程 eureka_service (子模块)中,运行启动类,进行测试

浏览器地址栏输入:http://localhost:9000 输出界面如下:

在这里插入图片描述

4、SpringCloudGateWay 网关:入门案例–搭建环境–在父工程 spring_cloud_demo 下,创建子工程 product_service(子模块)

4.1 创建 生产者 子工程 product_service(子模块)
	--> 右键 spring_cloud_demo 父工程--> Modules --> Maven --> Groupld : ( djh.it )Artifactld : ( product_service )Version : 1.0-SNAPSHOT--> Next --> Module name: ( product_service )Content root : ( spring_cloud_demo\product_service )Module file location: ( spring_cloud_demo\product_service )--> Finish
4.2 在 生产者 子工程 product_service (子模块)中的 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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>spring_cloud_demo</artifactId><groupId>djh.it</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>product_service</artifactId><dependencies><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><!--            <version>5.1.32</version>--><version>8.0.26</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!-- 引入 EurekaClient 依赖坐标 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency></dependencies></project><!-- spring_cloud_demo\product_service\pom.xml -->
4.3 在 生产者 子工程 product_service (子模块)中,创建 商品实体类 Product.java
/***   spring_cloud_demo\product_service\src\main\java\djh\it\product\domain\Product.java**  2024-4-17 商品实体类 Product.java*/
package djh.it.product.domain;import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.math.BigDecimal;@Data
@Entity
@Table(name="tb_product")  //对应数据库中的数据表
public class Product {@Idprivate Long id;private String productName;private Integer status;private BigDecimal price;private String productDesc;private String caption;private Integer inventory;
}
4.4 在 生产者 子工程 product_service (子模块)中,创建 dao 持久层接口类 ProductDao.java
/***   spring_cloud_demo\product_service\src\main\java\djh\it\product\dao\ProductDao.java**  2024-4-17  dao 持久层接口 ProductDao.java*/
package djh.it.product.dao;import djh.it.product.domain.Product;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;public interface ProductDaoextends JpaRepository<Product, Long>, JpaSpecificationExecutor<Product> {}
4.5 在 生产者 子工程 product_service (子模块)中,创建 service 服务层 接口类 ProductService.java
/***   spring_cloud_demo\product_service\src\main\java\djh\it\product\service\ProductService.java**  2024-4-17  service 服务层 接口 ProductService.java*/
package djh.it.product.service;import djh.it.product.domain.Product;public interface ProductService {//根据id查询Product findById(Long id);//保存void save(Product product);//更新void update(Product product);//删除void delete(Long id);
}
4.6、在 生产者 子工程 product_service (子模块)中,创建 service 服务层 实现类 ProductServiceImpl.java
/***   spring_cloud_demo\product_service\src\main\java\djh\it\product\service\Impl\ProductServiceImpl.java**  2024-4-17  service 服务层 实现类*/
package djh.it.product.service.Impl;import djh.it.product.domain.Product;
import djh.it.product.dao.ProductDao;
import djh.it.product.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class ProductServiceImpl implements ProductService {@Autowiredprivate ProductDao productDao;@Overridepublic Product findById(Long id) {return productDao.findById(id).get();}@Overridepublic void save(Product product) {productDao.save(product);}@Overridepublic void update(Product product) {productDao.save(product);}@Overridepublic void delete(Long id) {productDao.deleteById(id);}
}
4.7 在 生产者 子工程 product_service (子模块)中,创建 商品的 controller 类 ProductController.java
/***  C:\java-test\idea2019\spring_cloud_demo\product_service\src\main\java\djh\it\product\controller\ProductController.java**  2024-4-17 商品的 controller 类 ProductController.java*/
package djh.it.product.controller;import djh.it.product.domain.Product;
import djh.it.product.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/product")
public class ProductController {@Autowiredprivate ProductService productService;//获取服务器端口号@Value("${server.port}")private String port;//获取服务器IP地址@Value("${spring.cloud.client.ip-address}")   //springcloud 自动获取当前应用的IP地址private String ip;@RequestMapping(value = "/{id}", method = RequestMethod.GET)public Product findById(@PathVariable Long id){Product product = productService.findById(id);product.setProductName("访问的服务地址是:" + ip + " : " + port);return product;}@RequestMapping(value = "", method = RequestMethod.POST)public String save (@RequestBody Product product){productService.save(product);return "保存成功";}}
4.8 在 生产者 子工程 product_service (子模块)中,创建配置文件 application.yml
## C:\java-test\idea2019\spring_cloud_demo\product_service\src\main\resources\application.ymlserver:port: 9001  # 启动端口 命令行注入。
#  port: ${port:9001}  # 启动端口设置为动态传参,如果未传参数,默认端口为 9001
#  servlet:
#    context-path: /application1spring:application:name: service-product  #spring应用名, # 注意 FeignClient 不支持名字带下划线
#  main:
#    allow-bean-definition-overriding: true # SpringBoot2.1 需要设定。datasource:driver-class-name: com.mysql.jdbc.Driver  # mysql 驱动url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: 12311jpa:database: MySQLshow-sql: trueopen-in-view: trueeureka:  # 配置 Eurekaclient:service-url:defaultZone: http://localhost:9000/eureka/
#      defaultZone: http://localhost:9000/eureka/,http://localhost:8000/eureka/  # 高可用,注册多个 eurekaserver 用 , 隔开。instance:prefer-ip-address: true  # 使用 ip 地址注册instance-id: ${spring.cloud.client.ip-address}:${server.port}  # 向注册中心注册服务的id(IP 地址)。lease-renewal-interval-in-seconds: 10  # 设置向注册中心每10秒发送一次心跳,告诉注册中心此服务没有岩机,此参数默认是30秒。lease-expiration-duration-in-seconds: 20  # 设置每20秒如果注册中心没收到此服务的心跳,就认为此服务岩机了,此参数默认是90秒。
4.9 在 生产者 子工程 product_service (子模块)中,创建 启动类 ProductApplication.java
/***   C:\java-test\idea2019\spring_cloud_demo\product_service\src\main\java\djh\it\product\ProductApplication.java**   2024-4-17  启动类 ProductApplication.java*/
package djh.it.product;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;import java.io.Serializable;@SpringBootApplication
@EntityScan("djh.it.product.domain")
@EnableEurekaClient  //激活 EurekaClient, 同 @EnableDiscoveryClient 注解相同。
public class ProductApplication implements Serializable {//运行启动类,浏览器地址栏输入:localhost:9001/product/1  进行访问测试。public static void main(String[] args) {SpringApplication.run(ProductApplication.class, args);}
}
4.10 在 生产者 子工程 product_service (子模块)中,运行启动类,进行测试

浏览器地址栏输入:http://127.0.0.1:9001/product/1

输出 mysql 数据库的第一条记录:

在这里插入图片描述

5、SpringCloudGateWay 网关:入门案例–搭建环境–在父工程 spring_cloud_demo 下,创建子 order_service 工程(子模块)

5.1 创建 消费者 子工程 order_service(子模块)
	--> 右键 spring_cloud_demo 父工程--> Modules --> Maven --> Groupld : ( djh.it )Artifactld : ( order_service )Version : 1.0-SNAPSHOT--> Next --> Module name: ( order_service )Content root : ( \spring_cloud_demo\order_service )Module file location: ( \spring_cloud_demo\order_service )--> Finish
5.2 在消费者子工程(子模块) order_service 的 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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>spring_cloud_demo</artifactId><groupId>djh.it</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>order_service</artifactId><dependencies><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><!--            <version>5.1.32</version>--><version>8.0.26</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!-- 引入 EurekaClient 依赖坐标 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!-- 引入 spring-retry 请求重试 依赖坐标 --><dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId></dependency></dependencies></project>
<!-- spring_cloud_demo\order_service\pom.xml -->
5.3 在消费者子工程(子模块) order_service 中,创建配置文件 application.yml
## spring_cloud_demo\order_service\src\main\resources\application.ymlserver:port: 9002  # 启动端口 命令行注入。spring:application:name: service-order  #spring应用名, # 注意 FeignClient 不支持名字带下划线
#  main:
#    allow-bean-definition-overriding: true # SpringBoot2.1 需要设定。datasource:driver-class-name: com.mysql.jdbc.Driver  # mysql 驱动url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: 12311jpa:database: MySQLshow-sql: trueopen-in-view: trueeureka:  # 配置 Eurekaclient:service-url:defaultZone: http://localhost:9000/eureka/instance:prefer-ip-address: true  # 使用 ip 地址注册
5.4 在消费者子工程(子模块) order_service 中,创建 商品实体类 Product.java
/***  spring_cloud_demo\order_service\src\main\java\djh\it\order\domain\Product.java**  2024-4-19 商品实体类 Product.java*/
package djh.it.order.domain;import lombok.Data;
import java.math.BigDecimal;@Data
public class Product {private Long id;private String productName;private Integer status;private BigDecimal price;private String productDesc;private String caption;private Integer inventory;
}
5.5 在消费者子工程(子模块) order_service 中,创建 controller 类 OrderController.java
/***    spring_cloud_demo\order_service\src\main\java\djh\it\order\controller\OrderController.java**  2024-4-19 订单的 controller 类 OrderController.java*/
package djh.it.order.controller;import djh.it.order.domain.Product;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;@RestController
@RequestMapping("/order")
public class OrderController {// 注入 restTemplate 对象@Autowiredprivate RestTemplate restTemplate;/***  使用 基于 ribbon 的形式调用远程微服务:*  1、使用 @LoadBalanced 注解 声明 RestTemplate*  2、使用服务名称 service-product 替换 IP 地址 。** @param id* @return*/@RequestMapping(value = "/buy/{id}", method = RequestMethod.GET)public Product findById(@PathVariable Long id){Product product = null;//product = restTemplate.getForObject("http://127.0.0.1:9001/product/1", Product.class);product = restTemplate.getForObject("http://service-product/product/1", Product.class);return product;}
}
5.6 在消费者子工程(子模块) order_service 中,创建 启动类 OrderApplication.java
/***   C:\java-test\idea2019\spring_cloud_demo\order_service\src\main\java\djh\it\order\OrderApplication.java**   2024-4-19  启动类 OrderApplication.java*/
package djh.it.order;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;@SpringBootApplication
@EntityScan("djh.it.order.domain")
@EnableEurekaClient  //激活 EurekaClient, 同 @EnableDiscoveryClient 注解相同。
public class OrderApplication {/***  使用 spring 提供的 RestTemplate 发送 http 请求到商品服务。*      1)创建 RestTemplate 对象交给容器管理。*      2)在使用的时候,调用其方法完成操作(getXX, postXX)。     **/@LoadBalanced  //使用 基于 ribbon 的形式调用远程微服务:使用 @LoadBalanced 注解 声明 RestTemplate@Beanpublic RestTemplate restTemplate(){return new RestTemplate();}//运行启动类,浏览器地址栏输入:localhost:9002/order/buy/1  进行访问测试。public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}
}
5.7 运行启动类,进行测试

浏览器地址栏输入:http://127.0.0.1:9002/order/buy/1
输出 mysql 数据库的第一条记录:

在这里插入图片描述

6、SpringCloudGateWay 网关:入门案例–搭建环境–在父工程 spring_cloud_demo 下,创建子 api_gateway_service 工程(子模块)

6.1 创建 子工程 api_gateway_service(子模块)
	--> 右键 spring_cloud_demo 父工程--> Modules --> Maven --> Groupld : ( djh.it )Artifactld : ( api_gateway_service )Version : 1.0-SNAPSHOT--> Next --> Module name: ( api_gateway_service )Content root : ( \spring_cloud_demo\api_gateway_service )Module file location: ( \spring_cloud_demo\api_gateway_service )--> Finish
6.2 在子工程(子模块) api_gateway_service 的 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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>spring_cloud_demo</artifactId><groupId>djh.it</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>api_gateway_service</artifactId><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency></dependencies></project>
<!-- spring_cloud_demo\api_gateway_service\pom.xml -->
6.3 在子工程(子模块) api_gateway_service 中,创建配置文件 application.yml
##  spring_cloud_demo\api_gateway_service\src\main\resources\application.ymlserver:port: 8088  # 启动端口 命令行注入。
spring:application:name: api-gateway-service  #spring应用名, # 注意 FeignClient 不支持名字带下划线# 配置 SpringCloudGateway 的路由cloud:gateway:routes:  # 配置路由,路由Id,路由到微服务的 uri, 断言(判断条件)- id: product-serviceuri: http://127.0.0.1:9001predicates:- Path=/product/**
6.4 在子工程(子模块) api_gateway_service 中,创建 启动类 GatewayServerApplication.java
/***   spring_cloud_demo\api_gateway_service\src\main\java\djh\it\gateway\GatewayServerApplication.java**   2024-5-7  启动类 GatewayServerApplication.java*/package djh.it.gateway;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class GatewayServerApplication {public static void main(String[] args) {SpringApplication.run(GatewayServerApplication.class, args);}
}

7、SpringCloudGateway 路由:gateway 依赖问题和内置断言条件介绍

7.1 启动 父工程 spring_cloud_demo 下 全部子项目的启动类,进行测试:

会发现在启动 子工程 api_gateway_service(子模块) 时,idea 控制台抛出异常,如下:

在这里插入图片描述

7.2 在各子模块( eureka_service, product_service, order_service )中的 pom.xml 文件中,导入 web 依赖坐标后,同时注销掉父工程 spring_cloud_demo 中 pom.xml 文件中的 web 依赖,重新运行各子模块启动类,进行测试。
        <!-- springcloudgateway 的内部是通过 netty + webflux 实现。webflux 实现和 springmvc 存在冲突,需要注销掉父工程中的 web 依赖,在各子模块中导入 web 依赖。--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
7.3 浏览器地址栏输入:http://localhost:8088 相当于 http://127.0.0.1:9001 所以:http://localhost:8088/product/1 相当于 http://127.0.0.1:9001/product/1

在这里插入图片描述

7.4 SpringCloudGateway 路由:gateway 内置断言条件介绍
##  spring_cloud_demo\api_gateway_service\src\main\resources\application.ymlserver:port: 8088  # 启动端口 命令行注入。
spring:application:name: api-gateway-service  #spring应用名, # 注意 FeignClient 不支持名字带下划线# 配置 SpringCloudGateway 的路由cloud:gateway:routes:  # 配置路由,路由Id,路由到微服务的 uri, 断言(判断条件)- id: product-service   # 保持唯一uri: http://127.0.0.1:9001   # 目标微服务请求地址predicates:   # 断言(判断条件)设置- Path=/product/**   # 路由条件 path : 路由路径匹配条件。 # 即:http://localhost:8088/product/1 相当于 http://127.0.0.1:9001/product/1
#            - After=xxxxxx  # 路由断言之后匹配。
#            - Before=xxxxxx  # 路由断言之前匹配。
#            - Between=xxxx.xxxx  # 路由断言之间匹配。
#            - Cookie=chocolate, ch.p  # 路由断言 cookie 匹配,此 predicate 匹配给定名称(chocolate)和正则表达式(ch.p)
#            - Header=X-Request-Id, /d+  # 路由断言 Header 匹配,header 名称匹配 X-Request-Id,且正则表达式匹配 /d+
#            - Host=**.somehost.org, **.anotherhost.org  # 路由断言 Host 匹配,匹配 host 主机列表, ** 代表可变参数。
#            - Method=GET  # 路由断言 Method 匹配,匹配的是请求的 HTTP 方法。
#            # - Path=/foo/{segment},/bar/{segment}  # 路由断言匹配,{segment} 为可变参数。
#            - Query=baz   # 或 Query=foo,ba.  # 路由断言 Query 匹配,将请求的参数 param(bax)进行匹配,也可以进行 regexp 正则表达式匹配(参数包含 foo, 并且 foo 的值匹配 ba.)。
#            - RemoteAddr=192.168.1.1/24  # 路由断言 RemoteAddr 匹配,将匹配 192.168.1.1~192.168.1.254 之间的 ip 地址,其中 24 为子网掩码位。

上一节关联链接请点击:
# 从浅入深 学习 SpringCloud 微服务架构(十)–zuul(2)

这篇关于# 从浅入深 学习 SpringCloud 微服务架构(十一)--SpringCloudGateWay(1)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/970304

相关文章

基于SpringBoot+Mybatis实现Mysql分表

《基于SpringBoot+Mybatis实现Mysql分表》这篇文章主要为大家详细介绍了基于SpringBoot+Mybatis实现Mysql分表的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录基本思路定义注解创建ThreadLocal创建拦截器业务处理基本思路1.根据创建时间字段按年进

Java编译生成多个.class文件的原理和作用

《Java编译生成多个.class文件的原理和作用》作为一名经验丰富的开发者,在Java项目中执行编译后,可能会发现一个.java源文件有时会产生多个.class文件,从技术实现层面详细剖析这一现象... 目录一、内部类机制与.class文件生成成员内部类(常规内部类)局部内部类(方法内部类)匿名内部类二、

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Springboot @Autowired和@Resource的区别解析

《Springboot@Autowired和@Resource的区别解析》@Resource是JDK提供的注解,只是Spring在实现上提供了这个注解的功能支持,本文给大家介绍Springboot@... 目录【一】定义【1】@Autowired【2】@Resource【二】区别【1】包含的属性不同【2】@

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

Elasticsearch 在 Java 中的使用教程

《Elasticsearch在Java中的使用教程》Elasticsearch是一个分布式搜索和分析引擎,基于ApacheLucene构建,能够实现实时数据的存储、搜索、和分析,它广泛应用于全文... 目录1. Elasticsearch 简介2. 环境准备2.1 安装 Elasticsearch2.2 J

Java中的String.valueOf()和toString()方法区别小结

《Java中的String.valueOf()和toString()方法区别小结》字符串操作是开发者日常编程任务中不可或缺的一部分,转换为字符串是一种常见需求,其中最常见的就是String.value... 目录String.valueOf()方法方法定义方法实现使用示例使用场景toString()方法方法

Java中List的contains()方法的使用小结

《Java中List的contains()方法的使用小结》List的contains()方法用于检查列表中是否包含指定的元素,借助equals()方法进行判断,下面就来介绍Java中List的c... 目录详细展开1. 方法签名2. 工作原理3. 使用示例4. 注意事项总结结论:List 的 contain

Java实现文件图片的预览和下载功能

《Java实现文件图片的预览和下载功能》这篇文章主要为大家详细介绍了如何使用Java实现文件图片的预览和下载功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... Java实现文件(图片)的预览和下载 @ApiOperation("访问文件") @GetMapping("