OCP开源项目:Spring Cloud Gateway模块中动态路由的实现

org.springframework.boot

spring-boot-starter-actuator

org.springframework.cloud

spring-cloud-starter-netflix-hystrix

2.2.3 配置HostName的规则限流

目前只对user-center用户中心进行限流

spring:

cloud:

gateway:

discovery:

locator:

lowerCaseServiceId: true

enabled: true

routes:

=====================================

  • id: api-eureka

uri: lb://eureka-server

order: 8000

predicates:

  • Path=/api-eureka/**

filters:

  • StripPrefix=1

  • name: Hystrix

args:

name : default

fallbackUri: ‘forward:/defaultfallback’

  • id: api-user

uri: lb://user-center

order: 8001

predicates:

  • Path=/api-user/**

filters:

  • GwSwaggerHeaderFilter

  • StripPrefix=1

  • name: Hystrix

args:

name : default

fallbackUri: ‘forward:/defaultfallback’

  • name: RequestRateLimiter #对应 RequestRateLimiterGatewayFilterFactory

args:

redis-rate-limiter.replenishRate: 1 # 令牌桶的容积 放入令牌桶的容积每次一个

redis-rate-limiter.burstCapacity: 3 # 流速 每秒

key-resolver: “#{@ipAddressKeyResolver}” # SPEL表达式去的对应的bean

2.2.4 新增配置类RequestRateLimiterConfig

配置类新建在com.open.capacity.client.config路径下

package com.open.capacity.client.config;

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import reactor.core.publisher.Mono;

/**

  • 定义spring cloud gateway中的 key-resolver: “#{@ipAddressKeyResolver}” #SPEL表达式去的对应的bean

  • ipAddressKeyResolver 要取bean的名字

*/

@Configuration

public class RequestRateLimiterConfig {

/**

  • 根据 HostName 进行限流

  • @return

*/

@Bean(“ipAddressKeyResolver”)

public KeyResolver ipAddressKeyResolver() {

return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());

}

/**

  • 根据api接口来限流

  • @return

*/

@Bean(name=“apiKeyResolver”)

public KeyResolver apiKeyResolver() {

return exchange -> Mono.just(exchange.getRequest().getPath().value());

}

/**

  • 用户限流

  • 使用这种方式限流,请求路径中必须携带userId参数。

  • 提供第三种方式

  • @return

*/

@Bean(“userKeyResolver”)

KeyResolver userKeyResolver() {

return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst(“userId”));

}

}

2.2.5 压力测试

接下来配置东西弄完之后 我们开始进行压力测试,压力测试之前,由于new-api-gateway有全局拦截器 AccessFilter 的存在,如果不想进行登录就进行测试的。先把

“/api-auth/**” 的判断中的注释掉。接下来我们开用postman进行测试

@Override

public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

// TODO Auto-generated method stub

String accessToken = extractToken(exchange.getRequest());

if(pathMatcher.match(“//v2/api-docs/”,exchange.getRequest().getPath().value())){

return chain.filter(exchange);

}

if(!pathMatcher.match(“/api-auth/**”,exchange.getRequest().getPath().value())){

// if (accessToken == null) {

// exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);

// return exchange.getResponse().setComplete();

// }else{

// try {

// Map<String, Object> params = (Map<String, Object>) redisTemplate.opsForValue().get(“token:” + accessToken) ;

// if(params.isEmpty()){

// exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);

// return exchange.getResponse().setComplete();

// }

// } catch (Exception e) {

// exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);

// return exchange.getResponse().setComplete();

// }

// }

}

return chain.filter(exchange);

}

  • 1.打开postman 选择Collections 点击新建按钮

新建输入名称与描述

  • 2.点击新建的Collection 新建一个request

添加request添加request2

    1. 输入地址:127.0.0.1:9200/api-user/users-anon/login?username=admin

填入URL

  • 4.切换成Tests的tab下,选择右边Status code is 200选项,这里可以选择其他的方法,根据自己的api定义。

选择Status code is 200

  • 5.这里需要注意:操作完刚刚的数据,必须点击save进行保存,否则无法生效;

保存请求配置

请求配置

    1. 点击 Run,就可以查看结果,有五次成功,五次失败;限流成功返回429

运行结果运行结果

在前一章,我们已经做了简单spring cloud gateway 介绍 和 限流,接下来,spring cloud gateway最重要的,也是最为关键的 动态路由,首先,API网关负责服务请求路由、组合及协议转换,客户端的所有请求都首先经过API网关,然后由它将匹配的请求路由到合适的微服务,是系统流量的入口,在实际生产环境中为了保证高可靠和高可用,尽量避免重启,如果有新的服务要上线时,可以通过动态路由配置功能上线。

3. Spring Cloud Gateway动态路由实现


首先,springcloudgateway配置路由有2种方式:

  • yml配置文件

  • 面向对象配置(代码方式配置)

3.1 yml配置

yml配置

3.2 代码方式配置

代码方式配置

3.3 路由初始化

srping cloud gateway网关启动时,路由信息默认会加载内存中,路由信息被封装到RouteDefinition对象中,

org.springframework.cloud.gateway.route.RouteDefinition

RouteDefinition

该类有的属性为 :

@NotEmpty

private String id = UUID.randomUUID().toString();

//路由断言定义

@NotEmpty

@Valid

private List predicates = new ArrayList<>();

//路由过滤定义

@Valid

private List filters = new ArrayList<>();

//对应的URI

@NotNull

private URI uri;

private int order = 0;

一个RouteDefinition有个唯一的ID,如果不指定,就默认是UUID,多个RouteDefinition组成了gateway的路由系统,所有路由信息在系统启动时就被加载装配好了,并存到了内存里。

3.4 网关的自动配置

org.springframework.cloud.gateway.config.GatewayAutoConfiguration

4

//RouteLocatorBuilder 采用代码的方式注入路由

@Bean

public RouteLocatorBuilder routeLocatorBuilder(ConfigurableApplicationContext context) {

return new RouteLocatorBuilder(context);

}

//PropertiesRouteDefinitionLocator 配置文件路由定义

@Bean

@ConditionalOnMissingBean

public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(GatewayProperties properties) {

return new PropertiesRouteDefinitionLocator(properties);

}

//InMemoryRouteDefinitionRepository 内存路由定义

@Bean

@ConditionalOnMissingBean(RouteDefinitionRepository.class)

public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() {

return new InMemoryRouteDefinitionRepository();

}

//CompositeRouteDefinitionLocator 组合多种模式,为RouteDefinition统一入口

@Bean

@Primary

public RouteDefinitionLocator routeDefinitionLocator(List routeDefinitionLocators) {

return new CompositeRouteDefinitionLocator(Flux.fromIterable(routeDefinitionLocators));

}

@Bean

public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,

List GatewayFilters,

List predicates,

RouteDefinitionLocator routeDefinitionLocator) {

return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, GatewayFilters, properties);

}

//CachingRouteLocator 为RouteDefinition提供缓存功能

@Bean

@Primary

//TODO: property to disable composite?

public RouteLocator cachedCompositeRouteLocator(List routeLocators) {

return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators)));

}

装配yml文件的,它返回的是PropertiesRouteDefinitionLocator,该类继承了RouteDefinitionLocator,RouteDefinitionLocator就是路由的装载器,里面只有一个方法,就是获取路由信息的。

org.springframework.cloud.gateway.route.RouteDefinitionLocator

5

RouteDefinitionLocator 类图如下:

RouteDefinitionLocator 类图

子类功能描述:

  • CachingRouteDefinitionLocator:RouteDefinitionLocator包装类, 缓存目标RouteDefinitionLocator 为routeDefinitions提供缓存功能

  • CompositeRouteDefinitionLocator -RouteDefinitionLocator包装类,组合多种 RouteDefinitionLocator 的实现,为 routeDefinitions提供统一入口

  • PropertiesRouteDefinitionLocator-从配置文件(GatewayProperties 例如,YML / Properties 等 ) 读取RouteDefinition

  • RouteDefinitionRepository-从存储器( 例如,内存 / Redis / MySQL 等 )读取RouteDefinition

  • DiscoveryClientRouteDefinitionLocator-从注册中心( 例如,Eureka / Consul / Zookeeper / Etcd 等

推荐参考文章:https://www.jianshu.com/p/b02c7495eb5e

3.5 编写动态路由

新建数据脚本,在 sql目录下 02.oauth-center.sql

Structure for table “sys_gateway_routes”

DROP TABLE IF EXISTS sys_gateway_routes;

CREATE TABLE sys_gateway_routes

(

id char(32) NOT NULL COMMENT ‘id’,

uri VARCHAR(100) NOT NULL COMMENT ‘uri路径’,

predicates VARCHAR(1000) COMMENT ‘判定器’,

filters VARCHAR(1000) COMMENT ‘过滤器’,

order INT COMMENT ‘排序’,

description VARCHAR(500) COMMENT ‘描述’,

delFlag int(11) DEFAULT ‘0’ COMMENT ‘删除标志 0 不删除 1 删除’,

createTime datetime NOT NULL,

updateTime datetime NOT NULL,

PRIMARY KEY (id)

) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8mb4 COMMENT ‘服务网关路由表’;

/**

  • 路由实体类

*/

public class GatewayRoutes {

private String id;

private String uri;

private String predicates;

private String filters;

private Integer order;

private String description;

private Integer delFlag;

private Date createTime;

private Date updateTime;

//省略getter,setter

}

/**

  • 路由的Service类

*/

@Service

public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware, IDynamicRouteService {

/**

  • 新增路由

  • @param gatewayRouteDefinition

  • @return

*/

@Override

public String add(GatewayRouteDefinition gatewayRouteDefinition) {

GatewayRoutes gatewayRoutes = transformToGatewayRoutes(gatewayRouteDefinition);

gatewayRoutes.setDelFlag(0);

gatewayRoutes.setCreateTime(new Date());

gatewayRoutes.setUpdateTime(new Date());

gatewayRoutesMapper.insertSelective(gatewayRoutes);

gatewayRouteDefinition.setId(gatewayRoutes.getId());

redisTemplate.opsForValue().set(GATEWAY_ROUTES_PREFIX + gatewayRouteDefinition.getId(), JSONObject.toJSONString(gatewayRouteDefinition));

return gatewayRoutes.getId();

}

/**

  • 修改路由

  • @param gatewayRouteDefinition

  • @return

*/

@Override

public String update(GatewayRouteDefinition gatewayRouteDefinition) {

GatewayRoutes gatewayRoutes = transformToGatewayRoutes(gatewayRouteDefinition);

gatewayRoutes.setCreateTime(new Date());

gatewayRoutes.setUpdateTime(new Date());

gatewayRoutesMapper.updateByPrimaryKeySelective(gatewayRoutes);
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

做任何事情都要用心,要非常关注细节。看起来不起眼的、繁琐的工作做透了会有意想不到的价值。
当然要想成为一个技术大牛也需要一定的思想格局,思想决定未来你要往哪个方向去走, 建议多看一些人生规划方面的书籍,多学习名人的思想格局,未来你的路会走的更远。

更多的技术点思维导图我已经做了一个整理,涵盖了当下互联网最流行99%的技术点,在这里我将这份导图分享出来,以及为金九银十准备的一整套面试体系,上到集合,下到分布式微服务

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!
-1712181774755)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

做任何事情都要用心,要非常关注细节。看起来不起眼的、繁琐的工作做透了会有意想不到的价值。
当然要想成为一个技术大牛也需要一定的思想格局,思想决定未来你要往哪个方向去走, 建议多看一些人生规划方面的书籍,多学习名人的思想格局,未来你的路会走的更远。

更多的技术点思维导图我已经做了一个整理,涵盖了当下互联网最流行99%的技术点,在这里我将这份导图分享出来,以及为金九银十准备的一整套面试体系,上到集合,下到分布式微服务

[外链图片转存中…(img-m1NzZBBr-1712181774755)]

[外链图片转存中…(img-fLC7sHWC-1712181774756)]

[外链图片转存中…(img-Gwp8Ln5P-1712181774756)]

[外链图片转存中…(img-ABkukQT2-1712181774756)]

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值