spring-cloud-gateway 服务网关
Spring Cloud Gateway是Spring Cloud官方推出的第二代网关框架,取代Zuul网关。网关作为流量的,在微服务系统中有着非常作用,网关常见的功能有路由转发、权限校验、限流控制等作用。
Spring Cloud Gateway是Spring官方最新推出的一款基于Spring Framework 5,Project Reactor和Spring Boot 2之上开发的网关。与zuul1.0不同的是,gateway是异步非阻塞的(netty+webflux实现),zuul1.0是同步阻塞请求的。gateway的数据是封装在ServerWebExchange中,zuul是存放在RequestContext里的(这里是重点,圈起来!)Gateway相对于Zuul来说,在路由的配置上更加多样化,配置更加简便。
官方文档 : https://docs.spring.io/spring-cloud-gateway/docs/2.2.5.RELEASE/reference/html/#gateway-starter
Gateway 核心概念:
Route 路由,它是网关的基础元素,包含ID、目标URI、断言、过滤器组成,当前请求到达网关时,会通过Gateway Handler Mapping,基于断言进行路由匹配,当断言为true时,匹配到路由进行转发
Predicate,断言,学过java8的同学应该知道这个函数,它可以允许开发人员去匹配HTTP请求中的元素,一旦匹配为true,则表示匹配到合适的路由进行转发
Filter,过滤器,可以在请求发出的前后进行一些业务上的处理,比如授权、埋点、限流等。
Gateway 工作模型:
其中,predicate就是我们的匹配条件;而filter,就可以理解为一个无所不能的拦截器。有了这两个元素,再加上目标uri,就可以实现一个具体的路由了。客户端向 Spring Cloud Gateway 发出请求,如果请求与网关程序定义的路由匹配,则该请求就会被发送到网关 Web 处理程序,此时处理程序运行特定的请求过滤器链。过滤器之间用虚线分开的原因是过滤器可能会在发送代理请求的前后执行逻辑。所有 pre 过滤器逻辑先执行,然后执行代理请求;代理请求完成后,执行 post 过滤器逻辑。
Predicate 路由断言:
Spring Cloud Gateway将路由匹配为Spring WebFlux HandlerMapping基础设施的一部分。Spring Cloud Gateway包括许多内置的路由谓词工厂。所有这些谓词都匹配HTTP请求的不同属性。您可以使用逻辑和语句组合多个路由谓词工厂。
Gateway 的路由断言机制以 AbstractRoutePredicateFactory 为基础,实现了如下多种方式。再官方文档内提供了配置说明
Gateway 网关的实现:
要在项目中引入Spring Cloud Gateway,引入相关依赖,然后只需要一些简单的配置即可构建好一个 Gateway 网关服务。
1.引入依赖(基于 spring-cloud-dependencies Hoxton.SR4 版本)
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-gateway</artifactId>
- </dependency>
2. 以 PathRoutePredicateFactory 路由断言为例子演示,做以下配置:
- server:
- port: 9544
- spring:
- application:
- name: gateway-service
- cloud:
- gateway:
- enabled: true
- discovery:
- locator:
- enabled: false #gateway开启服务注册和发现的功能
- lowerCaseServiceId: true #请求路径上的服务名配置为小写
- routes:
- - id: ribbon-server
- uri: lb://RIBBON-SERVER #uri以lb://开头(lb代表从注册中心获取服务),后面接的就是你需要转发到的服务名称
- predicates:
- - Path=/demo/**
- filters:
- - StripPrefix=1 # 代表 Path 的值中将第一段舍弃,本例子就是转发的时候为 /** 将/demo 去除。
- eureka:
- client:
- service-url:
- defaultZone: http://localhost:7001/eureka/
- instance:
- instance-id: gateway-service
3.启动服务访问相关的路径即可看到效果。
自定义Predicate 路由断言的实现:
创建一个类,继承 AbstractRoutePredicateFactory 类,实现对应方法:
- @Component
- public class AuthRoutePredicateFactory extends AbstractRoutePredicateFactory<AuthRoutePredicateFactory.Config> {
- public AuthRoutePredicateFactory() {
- super(Config.class);
- }
- private static final String NAME_KEY = "name";
- private static final String VALUE_KEY = "value";
- @Override
- public List<String> shortcutFieldOrder() {
- //属性进行匹配对应
- return Arrays.asList(NAME_KEY, VALUE_KEY);
- }
- @Override
- public Predicate<ServerWebExchange> apply(Config config) {
- //Header中携带了某个值,进行header的判断
- return (exchange -> {
- HttpHeaders headers = exchange.getRequest().getHeaders();
- List<String> headerList = headers.get(config.getName());
- return headerList.size() > 0;
- });
- }
- public static class Config {
- private String name;
- private String value;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getValue() {
- return value;
- }
- public void setValue(String value) {
- this.value = value;
- }
- }
- }
yml 配置如下:
- spring:
- application:
- name: gateway-service
- cloud:
- gateway:
- enabled: true
- discovery:
- locator:
- enabled: false #gateway开启服务注册和发现的功能
- lowerCaseServiceId: true #请求路径上的服务名配置为小写
- routes:
- - id: cookie_route
- predicates:
- - Auth=Authorization,token
- filters:
- - StripPrefix=1
- uri: lb://RIBBON-SERVER
其中 Authorization 为 name,token 为 value,打个断点看看就行了。
Filter 请求过滤器:
Filter分为全局过滤器和路由过滤器,当请求与路由匹配时,过滤Web处理程序会将的所有实例GlobalFilter
和所有特定GatewayFilter
于路由的实例添加到过滤器链中。该组合的过滤器链按org.springframework.core.Ordered
接口排序,您可以通过实现该getOrder()
方法进行设置。
需要获取到更详细的信息可以惨开官网 :https://docs.spring.io/spring-cloud-gateway/docs/2.2.5.RELEASE/reference/html/#gatewayfilter-factories
这里演示一下自定义的过滤器(全局、路由)
1.全局过滤器只需要实现接口 org.springframework.cloud.gateway.filter.GlobalFilter,而后无需任何配置,即可生效。
- @Component
- public class CustomGlobalFilter implements GlobalFilter, Ordered {
- Logger logger= LoggerFactory.getLogger(CustomGlobalFilter.class);
- @Override
- public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
- logger.info("custom global filter");
- return chain.filter(exchange);
- }
- @Override
- public int getOrder() {
- return -1;
- }
- }
2.路由过滤器 需要继承 org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory
每个过滤器工厂都对应一个实现类,并且这些类的名称必须以 GatewayFilterFactory 结尾,这是Spring Cloud Gateway的一个约定,例如 AddRequestHeader 对应的实现类为 AddRequestHeaderGatewayFilterFactory
- @Component
- public class WuzzDefineGatewayFilterFactory extends AbstractGatewayFilterFactory<WuzzDefineGatewayFilterFactory.WuzzConfig>{
- private static final String NAME_KEY="name";
- Logger logger= LoggerFactory.getLogger(WuzzDefineGatewayFilterFactory.class);
- public WuzzDefineGatewayFilterFactory() {
- super(WuzzConfig.class);
- }
- @Override
- public List<String> shortcutFieldOrder() {
- return Arrays.asList(NAME_KEY);
- }
- @Override
- public GatewayFilter apply(WuzzConfig config) {
- //Filter pre post
- return ((exchange,chain)->{
- logger.info("[pre] Filter Request, name:"+config.getName());
- //TODO
- return chain.filter(exchange).then(Mono.fromRunnable(()->{
- //TODO
- logger.info("[post]: Response Filter");
- }));
- });
- }
- public static class WuzzConfig{
- private String name;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
- }
3. 配置路由规则
- spring:
- application:
- name: gateway-service
- cloud:
- gateway:
- enabled: true
- discovery:
- locator:
- enabled: false #gateway\u5F00\u542F\u670D\u52A1\u6CE8\u518C\u548C\u53D1\u73B0\u7684\u529F\u80FD
- lowerCaseServiceId: true #\u8BF7\u6C42\u8DEF\u5F84\u4E0A\u7684\u670D\u52A1\u540D\u914D\u7F6E\u4E3A\u5C0F\u5199
- routes:
- - id: config_route
- predicates:
- - Path=/demo/**
- filters:
- - StripPrefix=1
- - WuzzDefine=Hello Wuzz
- uri: lb://RIBBON-SERVER
4. 启动测试,发送一个请求,可以在控制台看到如下信息,说明过滤器均生效:
使用自带的限流过滤器 :
- spring:
- application:
- name: gateway-service
- cloud:
- gateway:
- enabled: true
- discovery:
- locator:
- enabled: false #gateway\u5F00\u542F\u670D\u52A1\u6CE8\u518C\u548C\u53D1\u73B0\u7684\u529F\u80FD
- lowerCaseServiceId: true #\u8BF7\u6C42\u8DEF\u5F84\u4E0A\u7684\u670D\u52A1\u540D\u914D\u7F6E\u4E3A\u5C0F\u5199
- routes:
- - id: config_route
- predicates:
- - Path=/demo/**
- filters:
- - StripPrefix=1
- - WuzzDefine=Hello Wuzz
- uri: lb://RIBBON-SERVER
- - id: ratelimiter_route
- predicates:
- - Path=/ratelimiter/**
- filters:
- - StripPrefix=1
- - name: RequestRateLimiter
- args:
- deny-empty-key: true
- keyResolver: '#{@ipAddressKeyResolver}'
- redis-rate-limiter.replenishRate: 1
- redis-rate-limiter.burstCapacity: 2
- uri: lb://RIBBON-SERVER
以上配置了限流过滤器,
- replenishRate:令牌桶中令牌的填充速度,代表允许每秒执行的请求数。
- burstCapacity:令牌桶的容量,也就是令牌桶最多能够容纳的令牌数。表示每秒用户最大能够执行的请求数量。
其中还需要配置一个 keyResolver:
- @Component
- public class IpAddressKeyResolver implements KeyResolver{
- @Override
- public Mono<String> resolve(ServerWebExchange exchange) {
- return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
- }
- }
然后启动测试,迅速刷新页面访问接口,会限流:
动态路由:
Spring Cloud Gateway 提供了 Endpoint 端点,暴露路由信息,有获取所有路由、刷新路由、查看单个路由、删除路由等方法,源码在 org.springframework.cloud.gateway.actuate.GatewayControllerEndpoint 中,想访问端点中的方法需要添加 spring-boot-starter-actuator 依赖,并在配置文件中暴露所有端点
- management:
- endpoints:
- web:
- exposure:
- include: "*"
列举几个常用的操作API 。详细信息及配置查看官方文档:https://docs.spring.io/spring-cloud-gateway/docs/2.2.5.RELEASE/reference/html/#actuator-api
- /actuator/gateway/routes GET 获取路由列表
- /actuator/gateway/globalfilters GET 全局过滤器列表
- /actuator/gateway/routefilters GET 路由过滤器列表
- /actuator/gateway/refresh POST 刷新新增的路由
- /gateway/routes/{id_route_to_create} POST/DELETS 新增或者删除
- ......
新增路由示例 :
然后调用一下 刷新的接口,即可生效。但是默认情况下,我们新增的路由只是保存在内存中,万一服务重启,则配置信息丢失,这个时候就需要将路由信息持久化。
路由持久化--基于redis
1. 引入 redis 依赖:
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-redis</artifactId>
- </dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>fastjson</artifactId>
- </dependency>
2. 实现 org.springframework.cloud.gateway.route.RouteDefinitionRepository 接口,重写路由的相关操作方法
- @Component
- public class RedisRouteDefinitionRepository implements RouteDefinitionRepository {
- private final static String GATEWAY_ROUTE_KEY="gateway_dynamic_route";
- @Autowired
- RedisTemplate<String,String> redisTemplate;
- @Override
- public Flux<RouteDefinition> getRouteDefinitions() {
- List<RouteDefinition> routeDefinitionList=new ArrayList<>();
- redisTemplate.opsForHash().values(GATEWAY_ROUTE_KEY).stream().forEach(route->{
- routeDefinitionList.add(JSON.parseObject(route.toString(),RouteDefinition.class));
- });
- return Flux.fromIterable(routeDefinitionList);
- }
- @Override
- public Mono<Void> save(Mono<RouteDefinition> route) {
- return route.flatMap(routeDefinition -> {
- redisTemplate.opsForHash().put(GATEWAY_ROUTE_KEY,routeDefinition.getId(),JSON.toJSONString(routeDefinition));
- return Mono.empty();
- });
- }
- @Override
- public Mono<Void> delete(Mono<String> routeId) {
- return routeId.flatMap(id->{
- if(redisTemplate.opsForHash().hasKey(GATEWAY_ROUTE_KEY,id)){
- redisTemplate.opsForHash().delete(GATEWAY_ROUTE_KEY,id);
- return Mono.empty();
- }
- return Mono.defer(()->Mono.error(new Exception("routeDefinition not found:"+routeId)));
- });
- }
- }
3.配置路由
- spring:
- application:
- name: gateway-service
- cloud:
- gateway:
- enabled: true
- discovery:
- locator:
- enabled: false #gateway\u5F00\u542F\u670D\u52A1\u6CE8\u518C\u548C\u53D1\u73B0\u7684\u529F\u80FD
- lowerCaseServiceId: true #\u8BF7\u6C42\u8DEF\u5F84\u4E0A\u7684\u670D\u52A1\u540D\u914D\u7F6E\u4E3A\u5C0F\u5199
- routes:
- - id: config_route
- predicates:
- - Path=/demo/**
- filters:
- - StripPrefix=1
- - WuzzDefine=Hello Wuzz
- uri: lb://RIBBON-SERVER
4. 测试,启动后按照之前一样创建一个路由,这个时候发现 redis里面已经保存了这个路由配置信息
也可以通过配置中心,比如 config 、Nacos 实现动态的配置。
spring-cloud-gateway 服务网关的更多相关文章
- Spring Cloud Gateway 服务网关快速上手
Spring Cloud Gateway 服务网关 API 主流网关有NGINX.ZUUL.Spring Cloud Gateway.Linkerd等:Spring Cloud Gateway构建于 ...
- Spring Cloud Gateway服务网关
原文:https://www.cnblogs.com/ityouknow/p/10141740.html Spring 官方最终还是按捺不住推出了自己的网关组件:Spring Cloud Gatewa ...
- spring cloud:服务网关 Spring Cloud GateWay 入门
Spring 官方最终还是按捺不住推出了自己的网关组件:Spring Cloud Gateway ,相比之前我们使用的 Zuul(1.x) 它有哪些优势呢?Zuul(1.x) 基于 Servlet,使 ...
- Spring Cloud (14) 服务网关-过滤器
Spring Cloud Zuul作为网关所具备的最基本的功能:路由,还具备另外一个核心的功能:过滤器. 过滤器 通过Spring Cloud Zuul实现的路由功能,我们的微服务可以通过统一的API ...
- Spring Cloud (12) 服务网关-基础
通过前几篇介绍,已经可以构建一个简单的微服务架构了,如下图: 通过eureka实现服务注册中心以及服务注册发现,通过ribbon或feign实现服务的消费以及负载均衡,通过spring cloud c ...
- Spring Cloud 之 服务网关
在微服务架构体系中,使用API 服务网关后的系统架构图如下: API服务网关的主要作用如下: 服务访问的统一入口 服务访问的负载均衡功能 服务访问的路由功能 在SpringCloud中,基于Netfl ...
- Spring Cloud (13) 服务网关-路由配置
传统路由配置 所谓传统路由配置方式就是在不依赖于服务发现机制情况下,通过在配置文件中具体制定每个路由表达式与服务实例的映射关系来实现API网关对外部请求的路由.没有Eureka服务治理框架帮助的时候, ...
- spring Cloud网关之Spring Cloud Gateway
Spring Cloud Gateway是什么?(官网地址:https://cloud.spring.io/spring-cloud-gateway/reference/html/) Spring C ...
- 熬夜肝了这篇Spring Cloud Gateway的功能及综合使用
前言 SpringCloud 是微服务中的翘楚,最佳的落地方案. Spring Cloud Gateway 是 Spring Cloud 新推出的网关框架,之前是 Netflix Zuul.网关通常在 ...
- Spring Cloud微服务中网关服务是如何实现的?(Zuul篇)
导读 我们知道在基于Spring Cloud的微服务体系中,各个微服务除了在内部提供服务外,有些服务接口还需要直接提供给客户端,如Andirod.IOS.H5等等. 而一个很尴尬的境地是,如果直接将提 ...
随机推荐
- Kyle Tedford :人,一定要懂得转弯
每个人都渴望成功,但成功之路不仅仅只有一条. 有的时候,有一条路人满为患,每个人都挤破脑袋想要过去,然而能过去者,却寥寥无几.但有的人,却知道适时转弯,在新的道路上,摸索前进,最终通往成功. 最近,星 ...
- 一次"内存泄漏"引发的血案
本文转载自一次"内存泄漏"引发的血案 导语 2017年末,手Q春节红包项目期间,为保障活动期间服务正常稳定,我对性能不佳的Ark Server进行了改造和重写.重编发布一段时间后, ...
- 国际标准时间格式ISO8601
日期表示法 年由4位数字组成YYYY,或者带正负号的四或五位数字表示±YYYYY.以公历公元1年为0001年,以公元前1年为0000年,公元前2年为-0001年,其他以此类推.应用其他纪年法要换算成公 ...
- MapReduce原理及简单实现
MapReduce是Google在2004年发表的论文<MapReduce: Simplified Data Processing on Large Clusters>中提出的一个用于分布 ...
- 手把手教你使用IDEA2020创建SpringBoot项目
一.New Project 二.如图选择Spring Initalizr,选择jdk版本,然后点击Next(注意:SpringBoot2开始至少使用JDK1.8) 三.如图根据自己需要修改,然后点击N ...
- 运行maven遇到的坑,差点崩溃了。
参考链接1:https://blog.csdn.net/lch_cn/article/details/8225448/ 参考链接2:https://jingyan.baidu.com/article/ ...
- JS判断年份是否为闰年
//闰年能被4整除且不能被100整除,或能被400整除.function year(){ if(year%4==0&&year%100!=0||year%400==0){ ...
- 使用PowerDesigner进行数据库设计并直接把设计好的表导出相应的建表语句
Power Designer:数据库表设计工具 PowerDesigner是Sybase公司的一款软件,使用它可以方便地对系统进行分析设计,他几乎包括了数据库模型设计的全过程.利用PowerDesig ...
- Vuex入门、同步异步存取值进阶版
关注公众号查看原文: 1. vueX介&绍安装 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方 ...
- Java基础语法:JavaDoc
一.简介 JavaDoc是一种将注释生成HTML文档的技术,它从程序源代码中抽取类.方法.成员等注释形成一个和源代码配套的API帮助文档. 也就是说,只要在编写程序时以一套特定的标签作注释,在程序编写 ...