思路:
1、在admin页面中的添加selector中对数据进行修改
2、shenyu内部通过发布对应的selectorEvent相关的事件同时修改对应的selector数据库表中该selector相关的数据内容
3、admin的事件发布触发shenyu网关中的相关事件,对应grpc插件内容进行处理时此时会重新在GrpcClientBuilder类中初始化ManagedChannel同时指定负载策略(动态修改时该策略由admin中页面修改后通过事件方式传递内容,该数据也就是selectorData实体),从selectorData中获取新的负载策略
代码修改:
admin、shenyu-common:
SelectorDTO类中添加字符类型字段 loadBalance
SelectorDO类中添加字符类型字段 loadBalance
SelectorData类中添加字符类型字段 loadBalance 同时有参类构造方法中进行数据赋值; 同时器静态内部类 Builder 同添加对loadBalance字段的方法数据设置
SelectorDO#buildSelectorDO()方法中设置传递的负载字段内容 selectorDO.setLoadBalance(selectorDTO.getLoadBalance());
SelectorDO#transFrom()方法中设置传递的负载字段内容 .loadBalance(selectorDO.getLoadBalance())
grpc-plugin:
GrpcPluginDataHandler#handlerSelector()
// 获取grpc插件中的Selector中的配置信息
@Override
public void handlerSelector(final SelectorData selectorData) {
if (Objects.isNull(selectorData.getName())) {
return;
}
// TODO 从SelectorData中获取到负载策略用于重新初始化客户端的负载方式
String loadBalance = selectorData.getLoadBalance();
// 初始化传递selectorName
GrpcClientCache.initGrpcClient(selectorData.getName(),loadBalance);
ApplicationConfigCache.getInstance().initPrx(selectorData);
}
GrpcClientBuilder#buildClient()
/**
* Build the client.
*
* @param contextPath contextPath - selectorName
* @return ShenyuGrpcClient shenyuGrpcClient
*/
public static ShenyuGrpcClient buildClient(final String contextPath, String loadBalance) {
// TODO 自定义修改负载策略
if (StringUtil.isNullOrEmpty(loadBalance)) {
loadBalance = LoadBalancerStrategy.RANDOM.getStrategy();
} else {
// 策略方式不是自定义中某一种
List<String> strategyNames = Arrays.stream(LoadBalancerStrategy.values()).map(item -> item.getStrategy()).collect(Collectors.toList());
// 全部转为小写方式比较策略名称
if (!strategyNames.contains(loadBalance.toLowerCase(Locale.ROOT))) {
loadBalance = LoadBalancerStrategy.RANDOM.getStrategy();
}
}
ManagedChannelBuilder<?> builder = ManagedChannelBuilder
// build channel to server with server's address
.forTarget(contextPath)
// 设置拦截器
.intercept(new ContextClientInterceptor())
// 设置默认的负载规则
.defaultLoadBalancingPolicy(loadBalance)
// 不会再去尝试升级http1
.usePlaintext()
// 消息传输大小限制
.maxInboundMessageSize(100 * 1024 * 1024)
//
.executor(buildExecutor())
// 关闭重试
.disableRetry();
ManagedChannel channel = builder.build();
channel.getState(true);
return new ShenyuGrpcClient(channel);
}
由于前台没有事先构造,postman中构造数据验证
{
"pluginId": "15",
"name": "/grpc",
"type": "1",
"matchMode": "0",
"continued": true,
"loged": false,
"enabled": true,
"sort": 1,
# handle中的数据为grpc服务端的权重和端口信息,端口值设置由客户端实现的GrpcServerBuilder接口实现类决定
"handle":" [{\"weight\":50,\"upstreamUrl\":\"192.168.43.156:38080\",\"status\":true},{\"weight\":50,\"upstreamUrl\":\"192.168.43.156:38081\",\"status\":true}]",
"selectorConditions": [
{
"id": "1676849893883617280",
"selectorId": "1676849893816508416",
"paramType": "uri",
"paramTypeName": "uri",
"operator": "startsWith",
"operatorName": "startsWith",
"paramName": "/",
"paramValue": "/grpc/",
"dateCreated": "2023-07-06 16:18:39",
"dateUpdated": "2023-07-06 16:18:39"
}
],
"id": "1676849893816508416",
# 添加的自定义字段动态决定负载均衡方式,自定义扩展grpc赋值策略可以仿照org.apache.shenyu.plugin.grpc.loadbalance包类型实现
"loadBalance": "random"
}
表结构修改