Refreshing Spring Cloud Gateway Route Cache on Service Instance Changes Using Nacos Events
The article explains why Spring Cloud Gateway may still call a downed service due to a stale CachingRouteLocator cache, and demonstrates how to listen to Nacos InstancesChangeEvent to evict the cache so the gateway always uses the latest service list.
Hello everyone, I'm Chen. Recently, members of my Knowledge Planet were studying the "Spring Cloud Alibaba" column and encountered an issue where a service went offline in a cluster but the gateway still routed requests to it, causing errors.
Root Cause
The gateway uses a CachingRouteLocator which caches routes. When a service is added or removed, the cache is not refreshed promptly, leading to stale routing information.
public class CachingRouteLocator implements Ordered, RouteLocator, ApplicationListener
, ApplicationEventPublisherAware {
private static final Log log = LogFactory.getLog(CachingRouteLocator.class);
private static final String CACHE_KEY = "routes";
private final RouteLocator delegate;
private final Flux
routes;
private final Map
cache = new ConcurrentHashMap<>();
private ApplicationEventPublisher applicationEventPublisher;
public CachingRouteLocator(RouteLocator delegate) {
this.delegate = delegate;
routes = CacheFlux.lookup(cache, CACHE_KEY, Route.class)
.onCacheMissResume(this::fetch);
}
private Flux
fetch() {
return this.delegate.getRoutes().sort(AnnotationAwareOrderComparator.INSTANCE);
}
@Override
public Flux
getRoutes() {
return this.routes;
}
/**
* Clears the routes cache.
* @return routes flux
*/
public Flux
refresh() {
this.cache.clear();
return this.routes;
}
@Override
public void onApplicationEvent(RefreshRoutesEvent event) {
try {
fetch().collect(Collectors.toList()).subscribe(list -> Flux.fromIterable(list)
.materialize().collect(Collectors.toList()).subscribe(signals -> {
applicationEventPublisher.publishEvent(new RefreshRoutesResultEvent(this));
cache.put(CACHE_KEY, signals);
}, throwable -> handleRefreshError(throwable)));
} catch (Throwable e) {
handleRefreshError(e);
}
}
private void handleRefreshError(Throwable throwable) {
if (log.isErrorEnabled()) {
log.error("Refresh routes error !!!", throwable);
}
applicationEventPublisher.publishEvent(new RefreshRoutesResultEvent(this, throwable));
}
@Deprecated
void handleRefresh() { refresh(); }
@Override
public int getOrder() { return 0; }
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
}Solution: listen to Nacos instance change events and evict the corresponding load‑balancer cache immediately, forcing Spring Cloud Gateway to fetch the latest service list.
Implementation
The following listener subscribes to InstancesChangeEvent and clears the cache for the affected service.
@Component
@Slf4j
public class NacosInstancesChangeEventListener extends Subscriber
{
@Resource
private CacheManager defaultLoadBalancerCacheManager;
@Override
public void onEvent(InstancesChangeEvent event) {
log.info("Spring Gateway received instance refresh event: {}, starting cache refresh", JacksonUtils.toJson(event));
Cache cache = defaultLoadBalancerCacheManager.getCache(SERVICE_INSTANCE_CACHE_NAME);
if (cache != null) {
cache.evict(event.getServiceName());
}
log.info("Spring Gateway instance refresh completed");
}
@Override
public Class
subscribeType() {
return InstancesChangeEvent.class;
}
}This listener obtains the service name from the event and evicts the corresponding entry in the load‑balancer cache (which implements Spring's Cache interface), ensuring that subsequent requests use the updated service list.
Feel free to test this approach in your own projects.
Final Note (Support the Author)
If you found this article helpful, please like, view, share, or bookmark it; your support motivates me to keep writing. I also run a Knowledge Planet where you can get discounted access to various Spring and microservice tutorials.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.