环境:
Java:8
Spring Boot:2.3.3
Spring Cloud:Hoxton.SR9
Spring Cloud Alibaba:2.2.2
动态路由操作工具类
@Service
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {
@Autowired
private RouteDefinitionWriter routeDefinitionWriter;
private ApplicationEventPublisher publisher;
/**
* 增加路由
*
* @param definition
* @return
*/
public String add(RouteDefinition definition) {
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "success";
}
/**
* 更新路由
*
* @param definition
* @return
*/
public String update(RouteDefinition definition) {
/*
* try { this.routeDefinitionWriter.delete(Mono.just(definition.getId())); } catch (Exception e) {
* return "update fail,not find route routeId: " + definition.getId(); }
*/
try {
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "success";
} catch (Exception e) {
return "update route fail";
}
}
/**
* 删除路由
*
* @param id
* @return
*/
public String delete(String id) {
try {
this.routeDefinitionWriter.delete(Mono.just(id)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "delete success";
} catch (Exception e) {
e.printStackTrace();
return "delete fail";
}
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
}
动态路由实现
@Slf4j
@Component
public class DynamicRouteServiceImplByNacos {
@Autowired
private DynamicRouteServiceImpl dynamicRouteService;
@Autowired
private GatewayConfig gatewayConfig;
@Autowired
private RouteDefinitionLocator routeDefinitionLocator;
@PostConstruct
public void init() {
dynamicRouteByNacosListener(gatewayConfig.getNacosRouteDataId(), gatewayConfig.getNacosRouteGroup());
}
/**
* 监听Nacos Server下发的动态路由配置
*
* @param dataId
* @param group
*/
public void dynamicRouteByNacosListener(String dataId, String group) {
try {
Properties properties = new Properties();
properties.setProperty("serverAddr", gatewayConfig.getNacosServerAddr());
properties.setProperty("namespace", gatewayConfig.getNacosNamespace());
ConfigService configService = NacosFactory.createConfigService(properties);
String configInfo = configService.getConfig(dataId, group, 5000);
log.info("获取网关当前路由配置 gatewayConfig={} configInfo={}", gatewayConfig, configInfo);
List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class);
for (RouteDefinition definition : definitionList) {
modifyMultiArgs(definition);
log.info("update route : {}", definition.toString());
dynamicRouteService.add(definition);
}
configService.addListener(dataId, group, new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
log.info("进行网关路由配置更新: {}", configInfo);
List<RouteDefinition> runningDefinitionList =
Optional.ofNullable(routeDefinitionLocator.getRouteDefinitions()).map(Flux::collectList)
.map(Mono::block).orElse(Collections.emptyList());
List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class);
for (RouteDefinition definition : definitionList) {
modifyMultiArgs(definition);
log.info("update route : {}", definition.toString());
dynamicRouteService.update(definition);
}
List<String> newRunningDefinitionIds =
definitionList.stream().map(RouteDefinition::getId).collect(Collectors.toList());
runningDefinitionList.stream().map(RouteDefinition::getId)
.filter(routId -> !newRunningDefinitionIds.contains(routId)).forEach(this::deleteRoute);
}
@Override
public Executor getExecutor() {
return null;
}
private void deleteRoute(String routeId) {
log.info("delete route : {}", routeId);
dynamicRouteService.delete(routeId);
}
});
} catch (NacosException e) {
log.error("网关动态路由配置出错", e);
}
}
private void modifyMultiArgs(RouteDefinition definition) {
List<PredicateDefinition> predicates = definition.getPredicates();
for (PredicateDefinition predicate : predicates) {
Map<String, String> predicateArgs = predicate.getArgs();
if (predicateArgs == null || predicateArgs.size() != 1) {
continue;
}
String[] args = StringUtils.tokenizeToStringArray(predicateArgs.values().iterator().next(), ",");
predicateArgs.clear();
for (int i = 0; i < args.length; i++) {
predicateArgs.put(NameUtils.generateName(i), args[i]);
}
}
}
}
modifyMultiArgs
直接使用fastjson将nacos传输的数据进行反序列化,发现官网中Path=/red/,/blue/这种多路径配置未生效,查看RouteDefinition及PredicateDefinition源码
public RouteDefinition() {
}
public RouteDefinition(String text) {
int eqIdx = text.indexOf('=');
if (eqIdx <= 0) {
throw new ValidationException("Unable to parse RouteDefinition text '" + text
+ "'" + ", must be of the form name=value");
}
setId(text.substring(0, eqIdx));
String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");
setUri(URI.create(args[0]));
for (int i = 1; i < args.length; i++) {
this.predicates.add(new PredicateDefinition(args[i]));
}
}
public PredicateDefinition() {
}
public PredicateDefinition(String text) {
int eqIdx = text.indexOf('=');
if (eqIdx <= 0) {
throw new ValidationException("Unable to parse PredicateDefinition text '"
+ text + "'" + ", must be of the form name=value");
}
setName(text.substring(0, eqIdx));
String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");
for (int i = 0; i < args.length; i++) {
this.args.put(NameUtils.generateName(i), args[i]);
}
}
发现在该方法的含参构造函数中,进行了相关处理,故增加对应逻辑,使多路径配置生效