# 从浅入深 学习 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

相关文章

java设计模式之工厂模式--普通工厂方法模式(Factory Method)

1.普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。 2.先定义一个接口: package com.zhong.pattern.factorymethod;/*** 发送接口* @author admin**/public interface Sender {/*** 发送消息方法* @param msg*/void send(String msg);} 3

Java设计模式之代理模式2-动态代理(jdk实现)

这篇是接着上一篇继续介绍java设计模式之代理模式。下面讲解的是jdk实现动态代理。 1.)首先我们要声明一个动态代理类,实现InvocationHandler接口 package com.zhong.pattern.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;/*** 演

java设计模式之代理模式1--静态代理

Java编程的目标是实现现实不能完成的,优化现实能够完成的,是一种虚拟技术。生活中的方方面面都可以虚拟到代码中。代理模式所讲的就是现实生活中的这么一个概念:助手。 代理模式的定义:给某一个对象提供一个代理,并由代理对象控制对原对象的引用。 1.)首先新建一个表演的接口 package com.zhong.pattern.proxy;/*** 表演接口* @author admin*

java原型(Prototype)设计模式

原型模式就是讲一个对象作为原型,使用clone()方法来创建新的实例。 public class Prototype implements Cloneable{private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}@Overri

Java中23种设计模式之适配者模式

适配器模式的作用就是在原来的类上提供新功能。 主要可分为3种: 1.类适配:创建新类,继承源类,并实现新接口,例如:     class Adapter extends OldClass implements NewFunc{} 2.对象适配:创建新类持源类的实例,并实现新接口,例如:     class Adapter implements NewFunc { priva

java不依赖临时变量交换两个变量的值

java不依赖临时变量交换两个变量的值 1.简单易懂的实现方式     int a=1,b=2;     int temp = 0;     temp = a;     a = b;     b= temp; 2.算术算法 int a=1,b=2; a = a+b;// a = 1+2  b = a-b;// b = a-b --> b=3-2 -->1 a = a -b;/

Java中的SOLID原则及示例

类是任何Java应用程序的构建块。如果这些区块不强,那么建筑(即应用)将来将面临艰难时期。这实际上意味着,当应用程序范围上升或应用程序在生产或维护中面临某些设计问题时,不那么好的编写会导致非常困难的情况。 另一方面,一组精心设计和编写的类可以加速编码过程的突飞猛进,同时减少错误的数量。 在本教程中,我们将使用 5个最推荐的设计原则的示例来讨论Java中的SOLID原则,在编写类时我们应该记住这

Java比较和交换示例 - CAS算法

Java比较和交换示例 - CAS算法 由Lokesh Gupta | 提起下:多线程 一个Java 5中最好添加的是支持类,如原子操作AtomicInteger,AtomicLong等等。这些课程帮助您最大限度地减少复杂的(非必要)需要多线程的,如增加一些基本的操作代码或递减的值在多个线程之间共享。这些类内部依赖于名为CAS(比较和交换)的算法。在本文中,我将详细讨论这个概念。 1.乐观和

java并发编程之CyclicBarrier(循环栅栏)

package com.zhong;import java.util.concurrent.CyclicBarrier;/*** Cyclic意思是循环,Barrier意思是屏障,那么CyclicBarrier翻译过来就是循环栅栏。* 它是一个同步辅助类,能让一组线程互相等待,* 直到这一组线程都到了一个公共屏障点,各线程才能继续向下执行。因为该屏障能够在释放等待线程后继续重用,所以叫循环屏障。*

Java内存管理 - 垃圾收集算法

我们都知道Java 中垃圾收集器 [GC] 的功能。但只有少数人试图深入了解垃圾收集的工作原理。你不是其中之一,这就是你在这里的原因。 在这个Java内存管理教程中,我们将尝试了解Java垃圾收集的当前算法,我们将了解这些算法的演变。 目录1. Java中的内存管理2.引用计数机制3.标记和清除机制4.停止并复制GC 5.分代停止和复制6.如何提高Java中的内存利用率 1.