服务发现
框架中的服务发现,应用的是 nacos 提供的。
nacos 提供的域的概念十分好用,可能很不便的将开发环境和本地环境辨别来开,有助于接口调试。
然而实现上也有一些毛病,那就是网关无奈获取到服务注册的事件,而且当服务启动时,网关会有几秒到十几秒的工夫,才可能发现注册的新服务,此时,才可能转发申请。
对于网关无奈获取到服务注册事件,Eureka
提供了 EurekalnstanceRegisteredEvent
、EurekalnstanceCanceledEvent
等事件能够判断。
然而我没有在 nacos 下找到相似的办法,对此一开始我的解决方案是,本人做一个检测服务类 cn.gateway.core.InstanceDetect
,将曾经注册上的服务保留,之后定时扫描,和保留的服务比照,如果新增就是注册胜利,如果不存在就是勾销注册。
不过最初,还是找到了绝对完满的解决办法,通过 NacosServiceManager
,在 InstanceRegisteredEvent
事件触发后,也就是网关自身注册到 nacos 后,nacosServiceManager.getNamingService(null)
这段代码才可能获取到 namingService
对象。
最初就能够通过 GatewayProperties
获取到所有的服务名称,再进行对应的订阅即可。
可能实现这一点,还是因为 nacos 和 gateway 都是基于 spring.application.name
作为注册服务和转发服务的根据。
@Serviceclass InstanceDetect( private val nacosServiceManager: NacosServiceManager, private val gatewayProperties: GatewayProperties) { @EventListener fun onApplicationEvent(event: InstanceRegisteredEvent<*>) { val namingService = nacosServiceManager.getNamingService(null) gatewayProperties.routes.forEach { val serviceInstanceMap = mutableMapOf<String, Instance>() namingService.subscribe(it.id) { event -> if (event !is NamingEvent) { return@subscribe } val serviceInstances = HashSet(serviceInstanceMap.keys) event.instances.forEach { instance -> if (serviceInstances.contains(instance.instanceId)) { serviceInstances.remove(instance.instanceId) } else { serviceInstanceMap[instance.instanceId] = instance log.info( "instance connected : {}, ip : {}, port : {}", instance.instanceId, instance.ip, instance.port ) } } for (removedInstance in serviceInstances) { val remove = serviceInstanceMap.remove(removedInstance)!! log.info( "instance disconnected : {}, ip : {}, port : {}", removedInstance, remove.ip, remove.port ) } } } }}
除此之外,客户端也提供了 RegisterEventListener
这个类,当客户端注册到 nacos 胜利时,打印一些信息。