关于zuul如何实现动态路由,已经有大神写博客详解过,这里不啰嗦了,文章地址:Spring Cloud Zuul实现动态路由,咱们就从这篇文章最后的一个问题讲起,作者在最后实现动态刷新路由规则时说:为什么不自己是手动重新加载Locator.dorefresh?非要用事件去刷新?这牵扯到内部的zuul内部组件的工作流程,不仅仅是Locator本身的一个变量,具体想要了解的还得去看源码。下面我们就来分析下zuul的源码看看为什么要这样做?
要讲清楚zuul的事件驱动模型,还得知道spring的事件驱动模型,因为zuul的实现正是利用了spring的事件驱动模型实现的。下面看看spring提供的事件模型图:
在zuul中有这样一个实现了ApplicationListener的监听器ZuulRefreshListener ,代码如下:
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) {
this.zuulHandlerMapping.setDirty(true);
}
else if (event instanceof HeartbeatEvent) {
if (this.heartbeatMonitor.update(((HeartbeatEvent) event).getValue())) {
this.zuulHandlerMapping.setDirty(true);
}
}
}
}
由此可知在发生ContextRefreshedEvent和RoutesRefreshedEvent事件时会执行this.zuulHandlerMapping.setDirty(true);
public void setDirty(boolean dirty) {
this.dirty = dirty;
if (this.routeLocator instanceof RefreshableRouteLocator) {
((RefreshableRouteLocator) this.routeLocator).refresh();
}
}
这样在spring容器启动完成后就刷新了路由规则。因此我们如果要主动刷新路由规则,只需要发布一个RoutesRefreshedEvent事件即可,代码如下
public void refreshRoute() {
RoutesRefreshedEvent routesRefreshedEvent = new RoutesRefreshedEvent(routeLocator);
this.publisher.publishEvent(routesRefreshedEvent);
logger.info("刷新了路由规则......");
}