共计 1626 个字符,预计需要花费 5 分钟才能阅读完成。
服务发现
框架中的服务发现,应用的是 nacos 提供的。
nacos 提供的域的概念十分好用,可能很不便的将开发环境和本地环境辨别来开,有助于接口调试。
然而实现上也有一些毛病,那就是网关无奈获取到服务注册的事件,而且当服务启动时,网关会有几秒到十几秒的工夫,才可能发现注册的新服务,此时,才可能转发申请。
对于网关无奈获取到服务注册事件,Eureka
提供了 EurekalnstanceRegisteredEvent
、EurekalnstanceCanceledEvent
等事件能够判断。
然而我没有在 nacos 下找到相似的办法,对此一开始我的解决方案是,本人做一个检测服务类 cn.gateway.core.InstanceDetect
,将曾经注册上的服务保留,之后定时扫描,和保留的服务比照,如果新增就是注册胜利,如果不存在就是勾销注册。
不过最初,还是找到了绝对完满的解决办法,通过 NacosServiceManager
,在 InstanceRegisteredEvent
事件触发后,也就是网关自身注册到 nacos 后,nacosServiceManager.getNamingService(null)
这段代码才可能获取到 namingService
对象。
最初就能够通过 GatewayProperties
获取到所有的服务名称,再进行对应的订阅即可。
可能实现这一点,还是因为 nacos 和 gateway 都是基于 spring.application.name
作为注册服务和转发服务的根据。
@Service
class 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 胜利时,打印一些信息。