整合Spring Cloud Gateway编码实践

519 阅读7分钟

本章节的讲解代码下载地址如下:

链接: https://pan.baidu.com/s/1kEHVjog45PztXxJNjSkpTA 
提取码: 14fu

接下来就通过实际的编码,把微服务网关整合到项目中,顺便来体验一下 Spring Cloud Gateway 的功能。

编码整合 Spring Cloud Gateway

接下来笔者将结合实际的编码,来讲解如何构建一个网关服务。本章节代码是在 spring-cloud-alibaba-multi-service-demo 模板项目的基础上修改的,具体步骤如下所示。

第一步,修改文件名称。

首先,修改项目名称为 spring-cloud-alibaba-gateway-demo,然后把各个 Module 中 pom.xml 文件的 artifactId 修改为 spring-cloud-alibaba-gateway-demo。

第二步,新建网关 Module 并引入 Spring Cloud Gateway 依赖。

新建一个 Module,命名为 gateway-demo,Java 代码的包名为 ltd.newbee.cloud。在该 Module 的 pom.xml 配置文件中增加 parent 标签,与上层 Maven 建立好关系。

然后打开 gateway-demo 项目中的 pom.xml 文件,在 dependencies 标签下引入 Spring Cloud Gateway 的依赖文件,新增代码如下:

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>


第三步,增加网关配置。

打开 gateway-demo 项目中的 application.properties 文件,主要是配置项目端口以及路由,配置项为 spring.cloud.gateway.routes.*,最终的配置文件内容如下:

server.port=8127
​
spring.cloud.gateway.routes[0].id=goods-demo-route
spring.cloud.gateway.routes[0].uri=http://localhost:8120
spring.cloud.gateway.routes[0].order=1
spring.cloud.gateway.routes[0].predicates[0]=Path=/goods/**
​
spring.cloud.gateway.routes[1].id=shopcart-demo-route
spring.cloud.gateway.routes[1].uri=http://localhost:8122
spring.cloud.gateway.routes[1].order=1
spring.cloud.gateway.routes[1].predicates[0]=Path=/shop-cart/**


这里主要是配置 gateway-demo 到 goods-service-demo 和 shopcart-service-demo 的路由信息。如果访问到网关项目的路径是以 / goods 开头,就路由到 goods-service-demo,该项目的 URL 为 http://localhost:8120。如果访问到网关项目的路径是以 / shop-cart 开头,就路由到 shopcart-service-demo,该项目的 URL 为 http://localhost:8122

另外,在 goods-service-demo 和 shopcart-service-demo 中分别新增两个接口用于测试。

在 NewBeeCloudGoodsAPI 类中新增如下代码:

@GetMapping("/goods/page/{pageNum}")
public String goodsList(@PathVariable("pageNum") int pageNum) {
  
  return  "请求goodsList,当前服务的端口号为" + applicationServerPort;
}


在 NewBeeCloudShopCartAPI 类中新增如下代码:

@GetMapping("/shop-cart/page/{pageNum}")
public String cartItemList(@PathVariable("pageNum") int pageNum) throws InterruptedException {
  
  return "请求cartItemList,当前服务的端口号为" + applicationServerPort;
}


第四步,验证网关是否正确整合。

依次启动 gateway-demo、goods-service-demo 和 shopcart-service-demo 这 3 个项目。启动成功后,打开浏览器验证网关的功能,在地址栏中依次输入如下地址进行测试。

http://localhost:8127/goods?goodsId=2025

http://localhost:8127/goods/page/2

http://localhost:8127/shop-cart?cartId=2035

http://localhost:8127/shop-cart/page/3

四次访问的最终结果如下图所示。

网关整合成功!

另外,有一个知识点需要注意:不要在网关 Module 中加入 spring-boot-starter-web 依赖,否则网关项目是无法正常启动的,报错内容如下:

***************************
APPLICATION FAILED TO START
***************************
​
Description:
​
Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway.


Spring 官方文档中也做了重点提示,内容如下:

Spring Cloud Gateway requires the Netty runtime provided by Spring Boot and Spring Webflux. It does not work in a traditional Servlet Container or when built as a WAR.

在使用 Spring Cloud Gateway 组件时,不能使用传统的 Servlet 容器,也不能打包成 war 包。

将网关服务整合到服务中心

前文中只是简单的整合网关和功能验证,并没有整合服务中心,即网关模块并没有被真正纳入到微服务架构中来。在配置文件中定义的路由地址是 “写死的”,这种做法在真实项目中肯定是不推荐的。接下来要做的就是把 Spring Cloud Gateway 也注册到服务中心,通过服务中心(本课程中的技术选型为 Nacos)把请求路由到对应的服务实例中。

新建网关模块并整合至 Nacos

新建一个 Module,命名为 gateway-demo2,Java 代码的包名为 ltd.newbee.cloud。在该 Module 的 pom.xml 配置文件中增加 parent 标签,与上层 Maven 建立好关系。然后打开 gateway-demo2 项目中的 pom.xml 文件,在 dependencies 标签下引入 Spring Cloud Gateway 和服务发现的依赖文件,最终代码如下:

<?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>
    <groupId>ltd.newbee.cloud</groupId>
    <artifactId>gateway-demo2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gateway-demo2</name>
    <description>Spring Cloud Alibaba Gateway Demo</description>
​
    <parent>
        <groupId>ltd.newbee.cloud</groupId>
        <artifactId>spring-cloud-alibaba-gateway-demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
​
    <properties>
        <java.version>1.8</java.version>
    </properties>
​
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
​
        <dependency>
          <groupId>com.alibaba.cloud</groupId>
          <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>
</project>

接下来修改 gateway-demo2 项目中的 application.properties 配置文件,增加服务发现的配置项和路由配置项,代码如下:

server.port=8129

spring.application.name=newbee-cloud-gateway-service

spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

spring.cloud.nacos.username=nacos

spring.cloud.nacos.password=nacos
​
spring.cloud.gateway.discovery.locator.enabled=true
spring.cloud.gateway.discovery.locator.lower-case-service-id=true
​
spring.cloud.gateway.routes[0].id=goods-service-route
spring.cloud.gateway.routes[0].uri=lb://newbee-cloud-goods-service
spring.cloud.gateway.routes[0].order=1
spring.cloud.gateway.routes[0].predicates[0]=Path=/goods/**
​
spring.cloud.gateway.routes[1].id=shopcart-service-route
spring.cloud.gateway.routes[1].uri=lb://newbee-cloud-shopcart-service
spring.cloud.gateway.routes[1].order=1
spring.cloud.gateway.routes[1].predicates[0]=Path=/shop-cart/**


本课程中,Spring Boot 项目的配置文件都是. properties 格式的。如果平时开发时习惯使用. yml 格式的配置文件,可自行修改。

路由配置与前文中介绍的区别不大,只是由 “写死” 的地址修改为对应服务的地址,这样就能通过服务发现机制路由到对应的服务实例中了。另外,就是地址前缀由 http 改为了 lb,表示将会启用负载均衡功能,微服务中负载均衡这个知识点的编码和源码,笔者都已经讲解过。

编码完成后,最终 spring-cloud-alibaba-gateway-demo 项目的目录结构如下图所示。

功能验证

接下来,需要启动 Nacos Server,然后依次启动 gateway-demo2、goods-service-demo 和 shopcart-service-demo 这 3 个项目。如果未能成功启动,开发者需要查看控制台中的日志是否报错,并及时确认问题和修复。启动成功后进入 Nacos 控制台,点击 “服务管理” 中的服务列表,可以看到列表中已经存在这三个服务的服务信息,如下图所示。

接着,打开浏览器验证网关的功能,在地址栏中依次输入如下地址进行测试。

http://localhost:8129/goods?goodsId=2025

http://localhost:8129/goods/page/2

http://localhost:8129/shop-cart?cartId=2035

http://localhost:8129/shop-cart/page/3

整合 Spring Cloud Gateway 报错 503

然而,此时的结果如下图所示。

并未获取到正确的结果,而是一个 503 的报错提示。

主要是因为 Spring Cloud Gateway 的相关依赖中并没有负载均衡器,因此无法正确将请求路由到对应的服务中。修改方式也比较简单,在 Gateway 项目的依赖文件中加上负载均衡器的依赖就可以,新增如下代码即可。

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>


添加后记得刷新一下 Maven 依赖,然后再重新启动这个项目,在浏览器中就能够获取到正确的数据了。

为什么要单独讲一下这个问题呢?主要是因为浏览器中报了这个错误,但是在网关项目的日志文件中并没有这个错误的异常信息栈,这就导致开发者们在看到这个问题后,无法判断出导致这个问题的具体原因,进而也无法知道如何去处理它。另外一点就是当前使用的技术栈,版本都比较高,有些问题在网络上还无法找到答案,因此笔者在这里复现了这个问题并介绍了处理方式。

现在,服务网关也整合到项目中来了。不过,仅仅整合和简单的配置是远远不够的,接下来,笔者将继续介绍 Spring Cloud Gateway 组件中的重要知识点——Predicate(断言)和 Filter(过滤器)。当然,读者如果有任何问题或者想要和笔者讨论的内容,都可以在评论区留下看法,笔者会根据读者的反馈和问题继续整理和完善本章节内容。

原文地址 juejin.cn