欢迎访问我的GitHub

https://github.com/zq2599/blog_demos

内容:所有原创文章分类汇总及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;

本篇概览

  • 本文是《Spring Cloud Gateway实战》系列的第二篇,通过前文咱们了解到Spring Cloud Gateway的核心是路由配置,然后在本地application.yml中配置了一条路由,但这种修改本地配置文件的方式缺乏灵活性,未必能满足灵活多变的业务需求,因此,本篇的目的就是找出本地配置之外的其他配置方式来,满足各种实际需求;
  • 总的来说以下三种方式都是常用的:
  1. 目标地址支持用服务名(取代之前的IP+端口);
  2. 支持在nacos上配置;
  3. 支持写代码的方式配置;
  • 另外还有一种更加灵活的配置方式:动态代理,因为涉及到不少的代码所以会单独出一篇文章详细介绍

源码下载

名称 链接 备注
项目主页 https://github.com/zq2599/blog_demos 该项目在GitHub上的主页
git仓库地址(https) https://github.com/zq2599/blog_demos.git 该项目源码的仓库地址,https协议
git仓库地址(ssh) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
  • 这个git项目中有多个文件夹,本篇的源码在spring-cloud-tutorials文件夹下,如下图红框所示:

准备工作

  • 正式开始前需要再做一点准备工作,整个《Spring Cloud Gateway实战》系列中,所有请求最后都会被路由到provider-hello这个web上去,该服务目前只有一个web接口/hello/str,现在咱们再给它增加一个,后面的实战会用到

  • 新增加的web接口来自LBTest.java,可见非常简单:

package com.bolingcavalry.provider.controller;

import com.bolingcavalry.common.Constants;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.Date; @RestController
@RequestMapping("/lbtest")
public class LBTest { private String dateStr(){
return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());
} /**
* 返回字符串类型
* @return
*/
@GetMapping("/str")
public String helloStr() {
return Constants.LB_PREFIX + ", " + dateStr();
}
}
  • 上述代码中的Constants.LB_PREFIX来自子工程common:
package com.bolingcavalry.common;

public interface Constants {
String HELLO_PREFIX = "Hello World";
String LB_PREFIX = "Load balance";
}
  • 写完代码后,先确保nacos已经启动

  • 在启动provider-hello工程,启动成功后去看nacos,确认已经注册:

  • 准备完毕,可以开始实战了

目标地址支持用服务名(取代之前的IP+端口)

  • 咱们从最简单的开始,先看前文的路由配置,如下图红框,目标地址是IP+端口:

  • 玩过Spring Cloud的您自然看出了问题所在:没有注册发现,确实,这样将地址和端口写死在配置文件中是不合适的,咱们先来解决这个问题;

  • 新增名为gateway-by-loadbalance的子工程,其pom.xml中的依赖情况如下,可见重点是spring-cloud-starter-loadbalancer

<dependencies>
<dependency>
<groupId>com.bolingcavalry</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 路由策略使用lb的方式是,这个依赖一定要有 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!--nacos:注册中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
  • 启动类的代码省去了(和前文的一样)

  • 配置信息如下,重点是uri的值lb://provider-hello,用了前缀lb:,后面的provider-hello就是在nacos注册的服务名:

server:
#服务端口
port: 8085
spring:
application:
name: gateway-by-loadbalance
cloud:
nacos:
# 注册中心的配置
discovery:
server-addr: 127.0.0.1:8848
gateway:
routes:
- id: path_route_lb
uri: lb://provider-hello
predicates:
- Path=/lbtest/**
  • 单元测试类:
package com.bolingcavalry.gateway;

import com.bolingcavalry.common.Constants;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.junit.jupiter.api.Assertions.assertTrue; @SpringBootTest
@ExtendWith(SpringExtension.class)
@AutoConfigureWebTestClient
public class HelloTest { @Autowired
private WebTestClient webClient; @Test
void testLoadBalance() {
webClient.get()
.uri("/lbtest/str")
.accept(MediaType.APPLICATION_JSON)
.exchange()
// 验证状态
.expectStatus().isOk()
// 验证结果,注意结果是字符串格式
.expectBody(String.class).consumeWith(result -> assertTrue(result.getResponseBody().contains(Constants.LB_PREFIX)));
}
}
  • 运行单元测试,通过,可见上述配置可以通过前缀lb:准确找到服务:

支持在nacos上配置

  • 将所有配置信息写在application.yml中有个问题:不能远程配置,这在应用数量较多的场景就不方便了,好在nacos提供了远程配置的能力,应用启动后可以从nacos取得自己的配置信息,咱们来试试

  • 新增名为gateway-nacos-config的子工程,其pom.xml中的依赖情况如下,请注意里面的中文注释,每指明了每一个依赖的作用:

<dependencies>
<dependency>
<groupId>com.bolingcavalry</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 使用bootstrap.yml的时候,这个依赖一定要有 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<!-- 路由策略使用lb的方式是,这个依赖一定要有 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!--nacos:配置中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--nacos:注册中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
  • 本地的配置文件bootstrap.yml,非常简单,就是nacos的地址和远程配置信息:
spring:
application:
name: gateway-nacos-config
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yml
group: DEFAULT_GROUP
  • 接下来再nacos增加一个配置文件,操作如下图红框:

  • 增加一个配置,要注意的地方如下(配置信息的文本稍后给出,便于复制):

  • 上图中完整的配置信息如下:
server:
port: 8083
spring:
cloud:
gateway:
routes:
- id: path_route_addr
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/**
- id: path_route_lb
uri: lb://provider-hello
predicates:
- Path=/lbtest/**
  • 测试类中的两个测试方法如下所示,和前面没有任何区别:
@Test
void testHelloPredicates() {
webClient.get()
.uri("/hello/str")
.accept(MediaType.APPLICATION_JSON)
.exchange()
// 验证状态
.expectStatus().isOk()
// 验证结果,注意结果是字符串格式
.expectBody(String.class).consumeWith(result -> assertTrue(result.getResponseBody().contains(Constants.HELLO_PREFIX)));
} @Test
void testLoadBalance() {
webClient.get()
.uri("/lbtest/str")
.accept(MediaType.APPLICATION_JSON)
.exchange()
// 验证状态
.expectStatus().isOk()
// 验证结果,注意结果是字符串格式
.expectBody(String.class).consumeWith(result -> assertTrue(result.getResponseBody().contains(Constants.LB_PREFIX)));
}
  • 运行单元测试类,测试通过,证明从nacos获取配置文件成功:

写代码的方式配置

  • 前面的几个例子,路由信息都是写在配置文件中的,其实还有一种方式:写代码配置路由,能自己写代码来配置,这灵活性就更强了

  • 新增名为gateway-by-code的子工程,其pom.xml文件参照前面工程的即可

  • 接下来的本例的重点,在配置类中增加一个RouteLocator类型的bean,通过以下代码即可增加一个路由:

package com.bolingcavalry.gateway.cofig;

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration
public class RouteConfig { @Bean
public RouteLocator customizeRoute(RouteLocatorBuilder builder) {
return builder
.routes()
.route(
// 第一个参数是路由的唯一身份
"path_route_lb",
// 第二个参数是个lambda实现,
// 设置了配套条件是按照请求路径匹配,以及转发地址,
// 注意lb://表示这是个服务名,要从
r -> r.path("/lbtest/**").uri("lb://provider-hello")
)
.build();
}
}
  • 上述代码只配置了一个路由,还有一个在配置文件中,这样就能验证代码和配置文件能不能同时生效了:
server:
#服务端口
port: 8084
spring:
application:
name: gateway-by-code
cloud:
nacos:
discovery:
# nacos服务地址
server-addr: 127.0.0.1:8848
gateway:
routes:
- id: path_route_addr
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/**
  • 测试类和之前工程的一模一样,就不占用篇幅了,依旧是两个测试方法testHelloPredicates和testLoadBalance

  • 执行单元测试可以顺利通过,证明代码配置路由没有问题:

  • 至此,负载均衡、nacos配置、代码配置的实例咱们都尝试过了,它们合起来会给实际生存环境的配置带来很大的方便,希望能够给您一些参考

缺陷和解决之道

  • 上述配置方式虽多,但有一个共同的问题:每当配置变动后,Gateway应用需要重启才能生效,这在请求不间断的生产环境是难以接受的
  • 为了让最新的路由配置能在Gateway应用不重启的前提下生效,接下来的文章咱们一起去探索动态路由是如何实现的

你不孤单,欣宸原创一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 数据库+中间件系列
  6. DevOps系列

欢迎关注公众号:程序员欣宸

微信搜索「程序员欣宸」,我是欣宸,期待与您一同畅游Java世界...

https://github.com/zq2599/blog_demos

Spring Cloud Gateway实战之二:更多路由配置方式的更多相关文章

  1. Spring Cloud Gateway实战之三:动态路由

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  2. Spring Cloud Gateway实战之一:初探

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 关于<Spring Cloud Gateway实 ...

  3. Spring Cloud Gateway实战之四:内置predicate小结

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  4. Spring Cloud Gateway实战之五:内置filter

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  5. Spring Cloud gateway 网关服务二 断言、过滤器

    微服务当前这么火爆的程度,如果不能学会一种微服务框架技术.怎么能升职加薪,增加简历的筹码?spring cloud 和 Dubbo 需要单独学习.说没有时间?没有精力?要学俩个框架?而Spring C ...

  6. Spring Cloud Gateway(七):路由谓词工厂WeightRoutePredicateFactory

    本文基于 spring cloud gateway 2.0.1 接上文 5.基于路由权重(weigth)的谓词工厂 Spring Cloud Gateway 提供了基于路由权重的断言工厂,配置时指定分 ...

  7. Spring Cloud Gateway(六):路由谓词工厂 RoutePredicateFactory

    本文基于 spring cloud gateway 2.0.1 1.简介 Spring Cloud Gateway 创建 Route 对象时, 使用 RoutePredicateFactory 创建 ...

  8. Spring Cloud Gateway(五):路由定位器 RouteLocator

    本文基于 spring cloud gateway 2.0.1 1.简介 直接 获取 路 由 的 方法 是 通过 RouteLocator 接口 获取. 同样, 该 顶 级 接口 有多 个 实现 类, ...

  9. Spring Cloud Gateway(四):路由定义定位器 RouteDefinitionLocator

    本文基于 spring cloud gateway 2.0.1 1.简介 RouteDefinitionLocator 是路由定义定位器的顶级接口,它的主要作用就是读取路由的配置信息(org.spri ...

随机推荐

  1. SonarScanner扫描Maven项目使用说明

    最近在学习使用sonar扫描代码,已经成功扫描python项目,而扫描java代码不成功. 在网上找到的扫描java项目文章,经过尝试之后也没有成功. 本人自己研究了sonar官方的使用说明文章,将其 ...

  2. Jmeter监控技术实战

    性能测试中监控的意义 为性能分析提供依据 监控方案 serverAgent jmeter的插件,监控颗粒度不高,界面简陋 服务器中启动 jmeter中添加插件 Nmon Grafana 优秀监控方案所 ...

  3. windows2012添加ssl证书

    第一步: 先下载   rewrite_x64_zh-cn.msi   ,并安装 (*这个是2.0版本,千万不要安装2.1版本,否则导致网站进程池全部关闭) https://www.microsoft. ...

  4. django url配置-反向解析-视图函数-HttpRequest对象-HttpResponse对象-cookies-session-redis缓存session

    """ --视图概述:-- 作用:视图接受WEB请求,并响应WEB请求 本质:视图就是一个python中的函数 响应: 1.网页: 一.重定向 二.错误视图 400,50 ...

  5. P4234-最小差值生成树【LCT】

    正题 题目链接:https://www.luogu.com.cn/problem/P4234 题目大意 给出\(n\)个点\(m\)条边的一张图.求一棵生成树使得最大边权减去最小边权最小. \(1\l ...

  6. Stream聚合函数

    Stream班介绍 幼稚园开学的第一天,各们家长把小朋友送到了园里,各位小朋友都你看看我,我看看你.有的嚎啕大哭,有的呆若木鸡....这里时候园长安排我拿来小本本记录入园的小朋友.... 记录小朋友 ...

  7. 【C++ Primer Plus】编程练习答案——第5章

    1 void ch5_1() { 2 using namespace std; 3 int small, big, sum{0}; 4 cout << "enter small ...

  8. MyBatis实现批量添加

    在进行后端的操作时,批量添加总是少不了,话不多说,下面贴上代码 Mybatis代码: <insert id="batchInsert" parameterType=" ...

  9. UE4技术总结——委托

    UE4技术总结--委托 目录 UE4技术总结--委托 一.定义 二.用法 2.1 声明与调用委托 2.1.1 单播委托 2.1.1.a 声明 2.1.1.b 绑定 2.1.1.c 执行委托 2.1.1 ...

  10. 《手把手教你》系列技巧篇(二十九)-java+ selenium自动化测试- Actions的相关操作上篇(详解教程)

    1.简介 有些测试场景或者事件,Selenium根本就没有直接提供方法去操作,而且也不可能把各种测试场景都全面覆盖提供方法去操作.比如:就像鼠标悬停,一般测试场景鼠标悬停分两种常见,一种是鼠标悬停在某 ...