nacos配置网关的动态路由
nacos配置网关的动态路由
1.为什么要配置动态路由
配置动态路由的核心目的是为了 提高系统的灵活性、可维护性和可扩展性,尤其是在微服务架构中,动态路由可以解决服务实例动态变化、多环境配置、灰度发布、故障隔离等问题。通过动态路由,可以实现路由规则的集中管理、实时生效和灵活调整,从而更好地支持业务需求的变化。
比如:
在项目中某个路由出现了问题需要修改,如果在配置文件application.yaml中修改,项目需要重新运行才能读取到最新的配置文件中的内容,那这时候的服务是无法正常工作的,这会影响的用户体验.配置动态路由后,只需要在nacos的配置文件中进行修改然后保存配置即可,无需重启项目
2.实现步骤
这里以黑马程序员的黑马商城项目为例.....
1.在网关服务的pom文件中引入对应的配置管理和共享配置文件的依赖坐标
<!--统一配置管理-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--加载bootstrap,共享配置文件所需的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
2.创建bootstrap.yaml文件,添加nacos的服务地址,这里我是用docker部署的nacos
spring:
application:
name: gateway
cloud:
nacos:
server-addr: 192.168.48.128
config:
file-extension: yaml
shared-configs:
- dataId: shared-log.yaml # 共享日志配置
shared-log.yaml是我的日志配置文件,在shared-configs下配置的文件就是服务所需共享的文件,这些文件是在nacos中已经配置好的
3.创建监听路由变化的配置类DynamicRouteLoader
package com.hmall.gateway.route;
import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.hmall.common.utils.CollUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;
@Slf4j
@Component
@RequiredArgsConstructor
public class DynamicRouteLoader {
/**
* 通过监听 Nacos 配置中心的路由配置文件(gateway-routes.json),动态更新 Spring Cloud Gateway 的路由规则
*/
private final RouteDefinitionWriter writer; // Spring Cloud Gateway 提供的接口,用于动态添加或删除路由定义
private final NacosConfigManager nacosConfigManager; // 从 Nacos 配置中心读取配置并监听配置变化
// 路由配置文件的id和分组
private final String dataId = "gateway-routes.json"; //配置文件的名称dataId
private final String group = "DEFAULT_GROUP"; //nacos默认的分组group
// 保存更新过的路由id
private final Set<String> routeIds = new HashSet<>();
@PostConstruct
public void initRouteConfigListener() throws NacosException {
// 1.注册监听器并首次拉取配置
String configInfo = nacosConfigManager.getConfigService()
.getConfigAndSignListener(dataId, group, 5000, new Listener() {
@Override
public Executor getExecutor() {
return null;
}
@Override
public void receiveConfigInfo(String configInfo) {
updateConfigInfo(configInfo);
}
});
// 2.首次启动时,更新一次配置
updateConfigInfo(configInfo);
}
private void updateConfigInfo(String configInfo) {
log.debug("监听到路由配置变更,{}", configInfo);
// 1.反序列化
List<RouteDefinition> routeDefinitions = JSONUtil.toList(configInfo, RouteDefinition.class);
// 2.更新前先清空旧路由
// 2.1.清除旧路由
for (String routeId : routeIds) {
writer.delete(Mono.just(routeId)).subscribe();
}
routeIds.clear();
// 2.2.判断是否有新的路由要更新
if (CollUtils.isEmpty(routeDefinitions)) {
// 无新路由配置,直接结束
return;
}
// 3.更新路由
routeDefinitions.forEach(routeDefinition -> {
// 3.1.更新路由
writer.save(Mono.just(routeDefinition)).subscribe();
// 3.2.记录路由id,方便将来删除
routeIds.add(routeDefinition.getId());
});
}
}
4.将原先网关的application.yaml配置文件中将路由规则删掉

5.在nacos配置中心配置路由规则


这里的Data ID就是我们添加的DynamicRouteLoader类中定义的Data ID,分组默认即可DEFAULT_GROUP,配置文件选择JSON

JSON的路由配置
[
{
"id": "item",
"predicates": [{
"name": "Path",
"args": {"_genkey_0":"/items/**", "_genkey_1":"/search/**"}
}],
"filters": [],
"uri": "lb://item-service"
},
{
"id": "cart",
"predicates": [{
"name": "Path",
"args": {"_genkey_0":"/carts/**"}
}],
"filters": [],
"uri": "lb://cart-service"
},
{
"id": "user",
"predicates": [{
"name": "Path",
"args": {"_genkey_0":"/users/**", "_genkey_1":"/addresses/**"}
}],
"filters": [],
"uri": "lb://user-service"
},
{
"id": "trade",
"predicates": [{
"name": "Path",
"args": {"_genkey_0":"/orders/**"}
}],
"filters": [],
"uri": "lb://trade-service"
},
{
"id": "pay",
"predicates": [{
"name": "Path",
"args": {"_genkey_0":"/pay-orders/**"}
}],
"filters": [],
"uri": "lb://pay-service"
}
]
为什么使用json格式配置动态路由
这里使用json去配置路由规则,这样在监听器中只需要使用JSON工具将json串解析为 字符串即可 List<RouteDefinition> routeDefinitions = JSONUtil.toList(configInfo, RouteDefinition.class); 也可以使用其他类型的配置,但解析时没有json方便
6.验证
验证思路(以item服务为例):
1.将配置文件中的item服务删除
在配置文件中编辑gateway-routes.json文件,将规则中的 item删除,然后点击发布

此时可以看到网关服务的控制台监听到路由规则发生变化(监听器)

2.在user服务中登录,获取token

3,携带token向网关服务发送item的请求(报错404,因为网关规则中找不到item请求规则)
注意,一定要向网关发送请求,网关去向匹配到的服务转发请求(我这里的网关服务端口为8080)

发送后发现显示404,找不到这个服务

4.将配置文件中的item服务恢复,然后点击发布

此时可以看到网关服务控制台监听到路由规则发生了变化,item添加上去了

重复第3步

此时可以网关将请求转发到了item服务并获取正确响应(不要重启任何服务,因为我们就是在测试不重启服务是否可以实现动态路由)
更多推荐



所有评论(0)