Spring Cloud Gateway实战之二:更多路由配置方式
欢迎访问我的GitHub
https://github.com/zq2599/blog_demos
内容:所有原创文章分类汇总及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;
本篇概览
- 本文是《Spring Cloud Gateway实战》系列的第二篇,通过前文咱们了解到Spring Cloud Gateway的核心是路由配置,然后在本地application.yml中配置了一条路由,但这种修改本地配置文件的方式缺乏灵活性,未必能满足灵活多变的业务需求,因此,本篇的目的就是找出本地配置之外的其他配置方式来,满足各种实际需求;
- 总的来说以下三种方式都是常用的:
- 目标地址支持用服务名(取代之前的IP+端口);
- 支持在nacos上配置;
- 支持写代码的方式配置;
- 另外还有一种更加灵活的配置方式:动态代理,因为涉及到不少的代码所以会单独出一篇文章详细介绍
源码下载
- 本篇实战中的完整源码可在GitHub下载到,地址和链接信息如下表所示(https://github.com/zq2599/blog_demos):
名称 | 链接 | 备注 |
---|---|---|
项目主页 | 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应用不重启的前提下生效,接下来的文章咱们一起去探索动态路由是如何实现的
你不孤单,欣宸原创一路相伴
欢迎关注公众号:程序员欣宸
微信搜索「程序员欣宸」,我是欣宸,期待与您一同畅游Java世界...
https://github.com/zq2599/blog_demos
Spring Cloud Gateway实战之二:更多路由配置方式的更多相关文章
- Spring Cloud Gateway实战之三:动态路由
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- Spring Cloud Gateway实战之一:初探
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 关于<Spring Cloud Gateway实 ...
- Spring Cloud Gateway实战之四:内置predicate小结
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- Spring Cloud Gateway实战之五:内置filter
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- Spring Cloud gateway 网关服务二 断言、过滤器
微服务当前这么火爆的程度,如果不能学会一种微服务框架技术.怎么能升职加薪,增加简历的筹码?spring cloud 和 Dubbo 需要单独学习.说没有时间?没有精力?要学俩个框架?而Spring C ...
- Spring Cloud Gateway(七):路由谓词工厂WeightRoutePredicateFactory
本文基于 spring cloud gateway 2.0.1 接上文 5.基于路由权重(weigth)的谓词工厂 Spring Cloud Gateway 提供了基于路由权重的断言工厂,配置时指定分 ...
- Spring Cloud Gateway(六):路由谓词工厂 RoutePredicateFactory
本文基于 spring cloud gateway 2.0.1 1.简介 Spring Cloud Gateway 创建 Route 对象时, 使用 RoutePredicateFactory 创建 ...
- Spring Cloud Gateway(五):路由定位器 RouteLocator
本文基于 spring cloud gateway 2.0.1 1.简介 直接 获取 路 由 的 方法 是 通过 RouteLocator 接口 获取. 同样, 该 顶 级 接口 有多 个 实现 类, ...
- Spring Cloud Gateway(四):路由定义定位器 RouteDefinitionLocator
本文基于 spring cloud gateway 2.0.1 1.简介 RouteDefinitionLocator 是路由定义定位器的顶级接口,它的主要作用就是读取路由的配置信息(org.spri ...
随机推荐
- php nginx 路径批量配置
* 假设 E:\upload 作为图片上传的位置 nginx 做web服务 * 创建文件conf.php 放到这个目录下 <?php function handleDir($it, &$ ...
- IdentityServer4[3]:使用客户端认证控制API访问(客户端授权模式)
使用客户端认证控制API访问(客户端授权模式) 场景描述 使用IdentityServer保护API的最基本场景. 我们定义一个API和要访问API的客户端.客户端从IdentityServer请求A ...
- Linux环境yum,安装MySQL
Linux 使用yum命令安装mysql [安装步骤] 1.先检查系统是否安装有mysql [root@localhost ~]#yum list installed mysql* [root@loc ...
- aizhan查询旁IP网站脚本
<?php print_r("-------------------------\r\n"); print_r("-------爱站旁站查询------\r\n&q ...
- Spring源码之创建AOP代理之增强器的获取
前言 在上一篇博文中我们说到了通过自定义配置完成了对AnnotationAwareAspectJAutoProxyCreator类型的自动注册,那么这个类究竟做了什么工作从而完成AOP的操作呢?首先我 ...
- 讲师征集| .NET Conf China 2021正式启动
最近社区小伙伴们一直在为11月即将在武汉举办的 第三届.NET中国峰会而忙碌,社区活动官网设计和开发工作还在进行,我们在国庆节的前一天晚上向社区正式启动了活动的序幕,也就是我们确定好了举办地点.时间, ...
- Zookeeper的选举机制和同步机制超详细讲解,面试经常问到!
前言 zookeeper相信大家都不陌生,很多分布式中间件都利用zk来提供分布式一致性协调的特性.dubbo官方推荐使用zk作为注册中心,zk也是hadoop和Hbase的重要组件.其他知名的开源中间 ...
- Python技法2:函数参数的进阶用法
1.关键字参数(positional argument)和位置参数(keyword argument) Python函数的参数根据函数在调用时(注意,不是函数定义时)传参的形式分为关键字参数和位置参数 ...
- 实战经验分享:使用 PyO3 来构建你的 Python 模块
PyO3 主要用于创建原生 Python 的扩展模块.PyO3 还支持从 Rust 二进制文件运行 Python 代码并与之交互,可以实现 rust 与 Python 代码共存.在一些对性能要求较高的 ...
- (googlechrome)未知错误导致安装失败,如果googlechrome....
https://jingyan.baidu.com/article/ea24bc39ffb699da63b33147.html#5827690-tsina-1-63512-fe183374908e7 ...