Spring Cloud Zuul 路由自动刷新原理

现象

发布新服务,然后在数据库配置了路由,使用服务路径访问404。然后重新发布新的服务,就可以继续访问得到

(1)配置了路由第一次访问

动态路由-应用重启前

(2)重新发布后访问

动态路由-应用重启后

分析

(1)查找RefreshableRouteLocator.refresh方法

@Component
public class NacosRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {

    public NacosRouteLocator(ServerProperties serverProperties, ZuulProperties properties) {
        super(serverProperties.getServlet().getContextPath(), properties);
    }

    @Override
    public void refresh() {
        doRefresh();
    }

    @Override
    protected Map<String, ZuulProperties.ZuulRoute> locateRoutes() {

        //默认从配置文件中加载路由信息
        //return super.locateRoutes());

        //定制路由, 可以使用db的配置管理进行路由
        Map<String, ZuulProperties.ZuulRoute> routesMap = DbUtils.loadRoutes();

        return routesMap;
    }
}

(2)ZuulHandlerMapping.setDirty方法

public class ZuulHandlerMapping extends AbstractUrlHandlerMapping {

    public void setDirty(boolean dirty) {
        this.dirty = dirty;
        if (this.routeLocator instanceof RefreshableRouteLocator) {
            ((RefreshableRouteLocator) this.routeLocator).refresh();
        }
    }
}

(3)ZuulRefreshListener.reset方法

private static class ZuulRefreshListener
        implements ApplicationListener<ApplicationEvent> {

    @Autowired
    private ZuulHandlerMapping zuulHandlerMapping;

    private HeartbeatMonitor heartbeatMonitor = new HeartbeatMonitor();

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ContextRefreshedEvent
                || event instanceof RefreshScopeRefreshedEvent
                || event instanceof RoutesRefreshedEvent
                || event instanceof InstanceRegisteredEvent) {
            reset();
        }
        else if (event instanceof ParentHeartbeatEvent) {
            ParentHeartbeatEvent e = (ParentHeartbeatEvent) event;
            resetIfNeeded(e.getValue());
        }
        else if (event instanceof HeartbeatEvent) {
            HeartbeatEvent e = (HeartbeatEvent) event;
            resetIfNeeded(e.getValue());
        }
    }

    private void resetIfNeeded(Object value) {
        if (this.heartbeatMonitor.update(value)) {
            reset();
        }
    }

    private void reset() {
        this.zuulHandlerMapping.setDirty(true);
    }
}

(4)发现ApplicationEvent

@Override
public void onApplicationEvent(ApplicationEvent event) {
    if (event instanceof ContextRefreshedEvent
            || event instanceof RefreshScopeRefreshedEvent
            || event instanceof RoutesRefreshedEvent
            || event instanceof InstanceRegisteredEvent) {
        reset();
    }
    else if (event instanceof ParentHeartbeatEvent) {
        ParentHeartbeatEvent e = (ParentHeartbeatEvent) event;
        resetIfNeeded(e.getValue());
    }
    else if (event instanceof HeartbeatEvent) {
        HeartbeatEvent e = (HeartbeatEvent) event;
        resetIfNeeded(e.getValue());
    }
}

可以看到,其中的实例注册事件RoutesRefreshedEventInstanceRegisteredEvent均会触发刷新路由。

(5)Eureka触发路由更新

// org.springframework.cloud.netflix.eureka.CloudEurekaClient#onCacheRefreshed
@Override
protected void onCacheRefreshed() {
    super.onCacheRefreshed();

    if (this.cacheRefreshedCount != null) { // might be called during construction and
        // will be null
        long newCount = this.cacheRefreshedCount.incrementAndGet();
        log.trace("onCacheRefreshed called with count: " + newCount);
        this.publisher.publishEvent(new HeartbeatEvent(this, newCount));
    }
}
@Override
// org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServiceRegistration#start
public void start() {
    // only set the port if the nonSecurePort or securePort is 0 and this.port != 0
    if (this.port.get() != 0) {
        if (this.registration.getNonSecurePort() == 0) {
            this.registration.setNonSecurePort(this.port.get());
        }

        if (this.registration.getSecurePort() == 0 && this.registration.isSecure()) {
            this.registration.setSecurePort(this.port.get());
        }
    }

    // only initialize if nonSecurePort is greater than 0 and it isn't already running
    // because of containerPortInitializer below
    if (!this.running.get() && this.registration.getNonSecurePort() > 0) {

        this.serviceRegistry.register(this.registration);

        this.context.publishEvent(new InstanceRegisteredEvent<>(this,
                this.registration.getInstanceConfig()));
        this.running.set(true);
    }
}
上一篇 Spring Cloud Zuul MySQL 实现动态路由以及手动刷新
下一篇 RabbitMQ七种队列模式介绍与应用场景(通俗易懂)
目录
文章列表
1 Android getContentResolver().query 获取文件路径NullPointerException
Android getContentResolver().query 获取文件路径NullPointerException
2
Flutter Widget之Image
Flutter Widget之Image
3
iOS热修复框架JSPatch
iOS热修复框架JSPatch
4
Vue更好的HTTP框架axios.js
Vue更好的HTTP框架axios.js
5
RestTemplate(httpclient)动态设置超时时间
RestTemplate(httpclient)动态设置超时时间
最新评论
一位WordPress评论者
一位WordPress评论者
2月12日
您好,这是一条评论。若需要审核、编辑或删除评论,请访问仪表盘的评论界面。评论者头像来自 Gravatar。