You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Cloud Gateway集成Eureka Client时路由意外刷新问题

解决Spring Cloud Gateway因Eureka心跳触发路由重建的问题

问题背景

网关接入Eureka服务发现后,每当Eureka客户端触发HeartbeatEvent事件时,内置的RouteRefreshListener会发布RefreshRoutesEvent,导致所有路由强制重建。由于自定义了RouteLocator从外部服务加载路由,频繁的路由重建对业务影响极大。已尝试配置spring.cloud.gateway.discovery.locator.enabled=false,但该配置仅关闭服务发现自动路由生成,无法阻止心跳触发的路由刷新。

核心原因

默认的RouteRefreshListener会监听HeartbeatEvent(Eureka心跳事件),当心跳状态更新时会触发路由全量重建,关键逻辑如下:

// 默认RouteRefreshListener的心跳事件处理
else if (event instanceof HeartbeatEvent) {
    HeartbeatEvent e = (HeartbeatEvent) event;
    resetIfNeeded(e.getValue());
}

解决方案

方案一:自定义RouteRefreshListener覆盖默认Bean

通过自定义同名Bean覆盖默认实现,移除对心跳事件的监听逻辑,只保留必要的路由刷新触发条件。

1. 实现自定义监听器

public class CustomRouteRefreshListener implements ApplicationListener<ApplicationEvent> {

    private final ApplicationEventPublisher publisher;

    public CustomRouteRefreshListener(ApplicationEventPublisher publisher) {
        Assert.notNull(publisher, "publisher may not be null");
        this.publisher = publisher;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        // 仅保留需要触发路由刷新的事件,移除心跳相关处理
        if (event instanceof ContextRefreshedEvent) {
            ContextRefreshedEvent refreshedEvent = (ContextRefreshedEvent) event;
            if (!WebServerApplicationContext.hasServerNamespace(
                    refreshedEvent.getApplicationContext(), "management")) {
                reset();
            }
        } else if (event instanceof RefreshScopeRefreshedEvent
                || event instanceof InstanceRegisteredEvent) {
            reset();
        }
        // 移除对HeartbeatEvent、ParentHeartbeatEvent的处理逻辑
    }

    private void reset() {
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
    }
}

2. 在自定义配置类中注册Bean

在你的RouteConfiguration中添加Bean定义,覆盖默认的RouteRefreshListener:

@Profile({"ui", "internal", "rec"})
@Configuration
public class RouteConfiguration {

    @Bean
    @RefreshScope
    public RouteLocator routeLocator(RouteLocatorBuilder routeLocatorBuilder, RouteLoader routeLoader) {
        return new RouteLocatorImpl(routeLocatorBuilder, routeLoader);
    }

    // 覆盖默认的RouteRefreshListener Bean
    @Bean
    public RouteRefreshListener routeRefreshListener(ApplicationEventPublisher publisher) {
        return new CustomRouteRefreshListener(publisher);
    }
}

方案二:完全禁用默认RouteRefreshListener

如果不需要任何自动触发的路由刷新,可以注册一个空实现的监听器,完全阻断自动刷新逻辑:

@Bean
public RouteRefreshListener routeRefreshListener(ApplicationEventPublisher publisher) {
    return new RouteRefreshListener(publisher) {
        @Override
        public void onApplicationEvent(ApplicationEvent event) {
            // 空实现,不处理任何事件
        }
    };
}

关键说明

  • spring.cloud.gateway.discovery.locator.enabled=false仅控制是否基于Eureka服务实例自动生成路由,与心跳触发的路由刷新无关,因此无法解决该问题。
  • 自定义监听器时可根据业务需求调整触发路由刷新的事件类型,例如仅保留配置刷新(RefreshScopeRefreshedEvent)或服务注册完成(InstanceRegisteredEvent)时的刷新逻辑。

内容的提问来源于stack exchange,提问作者Денис Дергачев

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 15:55:10