一、yml配置
server:
port: 8000
spring:
application:
name: micro-gateway
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: 127.0.0.1:8848
# 命名空间
namespace: e27b45b8-fd49-446e-a28a-a9112311837f
# 所属分组
group: SERVICE_GROUP
config:
# 配置中心地址
server-addr: ${spring.cloud.nacos.discovery.server-addr}
# 命名空间
namespace: ${spring.cloud.nacos.discovery.namespace}
# 所属分组
group: ${spring.cloud.nacos.discovery.group}
#配置文件格式
file-extension: yml
#共享配置,List集合,可以配置多个
shared-configs:
#配置动态更新网关路由信息
dynamic:
route:
address: ${spring.cloud.nacos.discovery.server-addr}
namespace: ${spring.cloud.nacos.discovery.namespace}
dataId: gateway-routes
group: DEFAULT_GROUP
timeout: 50000
二、Nacos配置文件
参加内容如下:
[
{
"id":"micro-system",
"uri":"lb://micro-system",
"predicates":[
{
"name":"Path",
"args":{
"pattern":"/micro-system/**"
}
}
],
"filters": [
{
"name":"StripPrefix",
"args":{
"pattern":1
}
}
]
},
{
"id":"micro-product",
"uri":"lb://micro-product",
"predicates":[
{
"name":"Path",
"args":{
"pattern":"/micro-product/**"
}
}
],
"filters": [
{
"name":"StripPrefix",
"args":{
"pattern":1
}
}
]
}
]
三、编写代码
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @Author lrp
* @date 2024-06-24 23:21
* @Description
*/
@Getter
@Setter
@Component
public class NacosConfig {
@Value("${spring.cloud.nacos.config.server-addr}")
private String serverAddr;
@Value("${spring.cloud.nacos.config.namespace}")
private String namespace;
@Value("#{'${spring.application.name}' + '${spring.profiles.active}'+'.yml'}")
private String dataId;
@Value("${spring.cloud.nacos.config.group}")
private String group;
//============= 动态路由配置 ==============
@Value("${dynamic.route.dataId}")
private String routeDataId;
@Value("${dynamic.route.group}")
private String routeGroup;
@Value("${dynamic.route.timeout}")
private Long timeout;
}
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import reactor.core.publisher.Mono;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @Author lrp
* @date 2024-06-24 17:31
* @Description 动态路由增删改方法
*/
@Component
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {
private final RouteDefinitionWriter routeDefinitionWriter;
private ApplicationEventPublisher publisher;
private static Set<String> routeIds = new HashSet<>();
public DynamicRouteServiceImpl(RouteDefinitionWriter routeDefinitionWriter) {
this.routeDefinitionWriter = routeDefinitionWriter;
}
/**
* 添加路由
*
* @param routeDefinition
* @return
*/
public String add(RouteDefinition routeDefinition) {
routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
routeIds.add(routeDefinition.getId());
return "success";
}
/**
* 更新路由
*
* @param routeDefinition
* @return
*/
public String update(RouteDefinition routeDefinition) {
try {
this.routeDefinitionWriter.delete(Mono.just(routeDefinition.getId()));
} catch (Exception e) {
return "update fail, not find route,routeId:" + routeDefinition.getId();
}
try {
routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "success";
} catch (Exception e) {
return "update fail";
}
}
/**
* 批量增加路由
*
* @param routeDefinitions
* @return
*/
public String addBatch(List<RouteDefinition> routeDefinitions) {
routeDefinitions.forEach(routeDefinition -> {
routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
routeIds.add(routeDefinition.getId());
});
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "success";
}
/**
* 批量更新路由
*
* @param routeDefinitions
* @return
*/
public String updateBatch(List<RouteDefinition> routeDefinitions) {
if (CollectionUtils.isEmpty(routeDefinitions)) {
return "success";
}
try {
routeIds.stream().forEach(routeIds->{
this.routeDefinitionWriter.delete(Mono.just(routeIds)).subscribe();
this.routeIds.remove(routeIds);
});
routeDefinitions.stream().forEach(routeDefinition -> {
routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
routeIds.add(routeDefinition.getId());
});
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "updateBatch success";
} catch (Exception e) {
return "updateBatch fail";
}
}
/**
* 删除路由
*
* @param id
* @return
*/
public String delete(String id) {
try {
this.routeDefinitionWriter.delete(Mono.just(id)).subscribe();
return "delete success";
} catch (Exception e) {
return "delete fail, not find route,routeId:" + id;
}
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
}
import com.alibaba.fastjson2.JSON;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.micro.gateway.config.NacosConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;
/**
* @Author lrp
* @date 2024-06-24 17:48
* @Description 动态路由配置
*/
@Slf4j
@RequiredArgsConstructor
@Component
public class DynamicRouteServiceImplByNacos implements CommandLineRunner {
private final DynamicRouteServiceImpl dynamicRouteService;
private final NacosConfig nacosConfig;
/**
* 监听nacos service下的动态路由配置
*/
public void dynamicRouteByNacosListener() {
try {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, nacosConfig.getServerAddr());
properties.put(PropertyKeyConst.NAMESPACE, nacosConfig.getNamespace());
ConfigService configService = NacosFactory.createConfigService(properties);
//程序启动的时候就从配置中心读取路由配置信息
String RouteContent = configService.getConfig(
nacosConfig.getRouteDataId(),
nacosConfig.getRouteGroup(),
nacosConfig.getTimeout());
log.info("初始化网关路由配置:\r\n{}", RouteContent);
//转json
List<RouteDefinition> list = JSON.parseArray(RouteContent, RouteDefinition.class);
if (!CollectionUtils.isEmpty(list)) {
dynamicRouteService.addBatch(list);
}
//添加配置信息更新监听器
configService.addListener(nacosConfig.getRouteDataId(),
nacosConfig.getRouteGroup(),
new Listener() {
@Override
public Executor getExecutor() {
return null;
}
@Override
public void receiveConfigInfo(String configInfo) {
log.info("接收到网关路由更新配置:\r\n{}", configInfo);
List<RouteDefinition> list = JSON.parseArray(configInfo, RouteDefinition.class);
dynamicRouteService.updateBatch(list);
}
});
} catch (NacosException e) {
throw new RuntimeException(e);
}
}
@Override
public void run(String... args) {
dynamicRouteByNacosListener();
}
}