gateway的服务注册路由默认是第一次启动的时候就加载,有个监听器RouteRefreshListener类,里面定义了一些事件,比如ContextRefreshEvent,HeartbeatEvent等事件,然后都会调用ApplicationEventPubilsher.publishEvent(new RereshRoutesEvent(this));这里应该就是程序启动时进行的路由刷新操作了。

然后gateway有一个刷新的endpoint,/actuator/gateway/refresh,可以找到这个控制器,里面也调用的ApplicationEventPubilsher.publishEvent(new RereshRoutesEvent(this));方法,这是spring的事件驱动,可以看出gateway都是通过这个事件来触发服务路由设置的。

顺着找到了监听事件的实现类,CachingRouteLocator,这同时也是gateway的缓存路由处理类,这是个包装类(路由配置来源有yaml配置,服务注册中心的配置,这里就包含了PropertiesRouteDefinitionLocator,DiscoveryClientRouteDefinitionLocator类),咱们是使用nacos根据服务发现自动配置的,所以咱们关注DiscoveryClientRouteDefinitionLocator这个类。

可以看到里面的getRouteDefinitions()方法,主要就是serviceInstances字段转换成routeDefinition的,而这个serviceInstances是通过DiscoveryClient.getServices()得来的,(这个DiscoveryClient和NacosReactiveDiscoveryClient可以去看我的关于spring和nacos服务注册相关的文章)。

这就是gateway加载nacos注册服务路由的流程。

这里就有个问题了,当nacos新注册一个服务的时候,gateway不知道,其实nacos有定义一个NacosWatch的bean,这个bean的会使用NamingService.subscribe(serviceName, groupName,clusterName,eventListener)向nacos注册一个监听器,NamingEvent(包含实例列表等信息)事件,然后向spring发送一个HeartbeatEvent事件,第一段说了这个事件,触发这个事件是可以刷新路由配置的,然而实际上并不是如此。

因为我们向nacos注册监听器的时候,有个参数是serviceName,这里默认取的就是当前服务名spring.application.name,只有当这个服务的实例发生变化时才通知,如果是一个新的服务,则不通知(这里我自己写了一个监听器,并监听了一个其他服务的名称,那个服务启动时,这边是会触发的)。

我用的nacos版本是2.x的,看了网上的一些文章,好像0.9版本的可以获取到所有服务的变更事件,难道nacos只能启动的时候获取服务列表,后面都不进行动态更新了?目前我还在找这个方法....

​​​​​​https://github.com/theonefx/s...

03-05 15:37