实现代码如下
package demo.assets.gateway.service;
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import java.util.List;
/**
* 动态更新路由网关service
* 1)实现一个Spring提供的事件推送接口ApplicationEventPublisherAware
* 2)提供动态路由的基础方法,可通过获取bean操作该类的方法。该类提供新增路由、更新路由、删除路由,然后实现发布的功能。
*/
@Slf4j
@Service
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {
@Autowired
private RouteDefinitionWriter routeDefinitionWriter;
@Autowired
private RouteDefinitionLocator routeDefinitionLocator;
/**
* 发布事件
*/
@Autowired
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
publisher = applicationEventPublisher;
}
/**
* 删除路由
* @param id
* @return
*/
public String delete(String id) {
try {
log.info("gateway delete route id {}",id);
this.routeDefinitionWriter.delete(Mono.just(id)).subscribe();
publisher.publishEvent(new RefreshRoutesEvent(this));
return "delete success";
} catch (Exception e) {
return "delete fail";
}
}
/**
* 更新路由
* @param definitions
* @return
*/
public String updateList(List<RouteDefinition> definitions) {
log.info("gateway update route {}",definitions);
// 删除缓存routerDefinition
List<RouteDefinition> routeDefinitionsExits = routeDefinitionLocator.getRouteDefinitions().buffer().blockFirst();
if (!CollectionUtils.isEmpty(routeDefinitionsExits)) {
routeDefinitionsExits.forEach(routeDefinition -> {
log.info("delete routeDefinition:{}", routeDefinition);
delete(routeDefinition.getId());
});
}
definitions.forEach(definition -> {
updateById(definition);
});
return "success";
}
/**
* 更新路由
* @param definition
* @return
*/
public String updateById(RouteDefinition definition) {
try {
log.info("gateway update route {}",definition);
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();
publisher.publishEvent(new RefreshRoutesEvent(this));
return "success";
} catch (Exception e) {
return "update route fail";
}
}
/**
* 增加路由
* @param definition
* @return
*/
public String add(RouteDefinition definition) {
try {
log.info("gateway add route {}",new RefreshRoutesEvent(this));
routeDefinitionWriter.delete(Mono.just(definition.getId()));
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
publisher.publishEvent(new RefreshRoutesEvent(this));
return "success";
} catch (Exception e){
// e.printStackTrace();
log.error("gateway add route error:{}",definition.getId());
}
return "fail";
}
}
具体报错如下:
reactor.core.Exceptions$ErrorCallbackNotImplemented: java.util.ConcurrentModificationException
Caused by: java.util.ConcurrentModificationException: null
at java.util.LinkedHashMap$LinkedHashIterator.nextNode(LinkedHashMap.java:711) ~[na:1.8.0_91]
at java.util.LinkedHashMap$LinkedValueIterator.next(LinkedHashMap.java:739) ~[na:1.8.0_91]
at reactor.core.publisher.FluxIterable$IterableSubscription.poll(FluxIterable.java:415) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxMergeSequential$MergeSequentialMain.drain(FluxMergeSequential.java:399) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxMergeSequential$MergeSequentialMain.innerComplete(FluxMergeSequential.java:321) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxMergeSequential$MergeSequentialInner.onComplete(FluxMergeSequential.java:576) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxFilter$FilterSubscriber.onComplete(FluxFilter.java:160) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onComplete(FluxMap.java:262) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxFilter$FilterConditionalSubscriber.onComplete(FluxFilter.java:293) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.checkTerminated(FluxFlatMap.java:838) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.drainLoop(FluxFlatMap.java:600) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.innerComplete(FluxFlatMap.java:909) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxFlatMap$FlatMapInner.onComplete(FluxFlatMap.java:1013) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1765) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.MonoCollectList$MonoCollectListSubscriber.onComplete(MonoCollectList.java:121) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxFirstNonEmptyEmitting$FirstNonEmptyEmittingSubscriber.onComplete(FluxFirstNonEmptyEmitting.java:333) ~[spring-cloud-commons-2.2.3.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxSubscribeOn$SubscribeOnSubscriber.onComplete(FluxSubscribeOn.java:159) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxIterable$IterableSubscription.fastPath(FluxIterable.java:357) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:222) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxSubscribeOn$SubscribeOnSubscriber.requestUpstream(FluxSubscribeOn.java:124) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxSubscribeOn$SubscribeOnSubscriber.onSubscribe(FluxSubscribeOn.java:117) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:161) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:86) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.Flux.subscribe(Flux.java:8325) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxFlatMap.trySubscribeScalarMap(FluxFlatMap.java:199) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.MonoFlatMapMany.subscribeOrReturn(MonoFlatMapMany.java:49) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxFromMonoOperator.subscribe(FluxFromMonoOperator.java:76) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.publisher.FluxSubscribeOn$SubscribeOnSubscriber.run(FluxSubscribeOn.java:187) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:84) [reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:37) [reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE
经过调试最终发现报错代码为下面几处发布事件的代码中:
百度无果,然后自己尝试调整代码,解决报错问题,
解决方案是把发布事件的代码移到循环之外,循环完之后再发布更新事件
修改代码如下,所有发布事件的地方修改方法同理
全部改完之后运行重启gateway,运行结果如下
gateway运行正常,不再报
2022-08-05 17:32:05.756 ERROR 22360 --- [oundedElastic-2] reactor.core.scheduler.Schedulers : Scheduler worker in group main failed with an uncaught exception
reactor.core.Exceptions$ErrorCallbackNotImplemented: java.util.ConcurrentModificationException
Caused by: java.util.ConcurrentModificationException: null 错误
至此问题解决,在此记录下,希望能帮到遇到同样问题的小伙伴们,小白初学,这个问题的具体原因不详,还请知道的大佬指点