Nacos 版本
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
Gateway 版本
<groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> <version>3.1.1</version>
-
gateway 服务配置
在Nacos 管理端下线服务后,Nacos服务端有定时延迟机制导致不能及时更新状态,导致服务重启后gateway网关依然会把请求分配到已经下线且停机的服务,导致接口提示未找到服务
此时需要更改gateway服务配置,定制自己的监听事件
增加MySubscribeConfig配置文件
/resources/META-INF 下增加spring.factories配置文件,内容如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.daishu.gateway.config.MySubscribeConfig
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.daishu.common.core.utils.SpringContextHolder;
import com.daishu.gateway.config.loadbalancer.MyNacosEventListener;
import com.daishu.gateway.config.loadbalancer.MyNacosSubscribe;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.cloud.loadbalancer.cache.LoadBalancerCacheManager;
import org.springframework.cloud.loadbalancer.config.LoadBalancerCacheAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* 首先订阅当前网关关注的服务
* nacos服务更新通知,但是gateway有一套自己的服务缓存列表。每次接到通知更新不及时导致转发到已经下线的服务
* gateway获取缓存参考:org.springframework.cloud.loadbalancer.core.CachingServiceInstanceListSupplier
* nacos订阅参考:com.alibaba.cloud.nacos.discovery.NacosWatch#start()
*
*/
@Configuration
@Import(SpringContextHolder.class)
@AutoConfigureAfter(LoadBalancerCacheAutoConfiguration.class)
public class MySubscribeConfig {
@Bean
public MyNacosSubscribe getMyNacosSubscribe(NacosServiceManager nacosServiceManager, NacosDiscoveryProperties properties){
LoadBalancerCacheManager cacheManager = SpringContextHolder.getBean(LoadBalancerCacheManager.class);
return new MyNacosSubscribe(nacosServiceManager,properties,new MyNacosEventListener(cacheManager));
}
}
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.nacos.api.naming.NamingService;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import java.util.HashSet;
import java.util.Set;
/**
* 订阅nacos推送更新事件
* 启动和加载路由时重新订阅
*/
public class MyNacosSubscribe implements ApplicationRunner {
private NacosServiceManager nacosServiceManager;
private NacosDiscoveryProperties properties;
private MyNacosEventListener myEventListener;
private Set<String> getRouteServices(){
// 这里返回自己要订阅的服务名称
Set<String> serviceName=new HashSet<>();
serviceName.add("server-name");
return serviceName;
}
// 这里监听时间是为了在路由信息修改时候,重新订阅服务的。如果说路由重新加载不会有订阅变动的话,可以去掉
@org.springframework.context.event.EventListener({RefreshRoutesEvent.class})
public void subscribe() {
NamingService namingService = nacosServiceManager
.getNamingService(properties.getNacosProperties());
try {
Set<String> services = getRouteServices();
if(CollectionUtil.isNotEmpty(services)){
for (String service : services) {
namingService.subscribe(service, properties.getGroup(),
null, myEventListener);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run(ApplicationArguments args) throws Exception {
subscribe();
}
public MyNacosSubscribe(NacosServiceManager nacosServiceManager, NacosDiscoveryProperties properties, MyNacosEventListener myEventListener) {
this.nacosServiceManager = nacosServiceManager;
this.properties = properties;
this.myEventListener = myEventListener;
}
import com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery;
import com.alibaba.nacos.api.naming.listener.Event;
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import com.alibaba.nacos.api.naming.pojo.Instance;
import org.springframework.cache.Cache;
import org.springframework.cloud.loadbalancer.cache.LoadBalancerCacheManager;
import org.springframework.cloud.loadbalancer.core.CachingServiceInstanceListSupplier;
import java.util.List;
/**
* 处理nacos推送更新事件
*/
public class MyNacosEventListener implements EventListener {
private LoadBalancerCacheManager loadBalancerCacheManager;
@Override
public void onEvent(Event event) {
try {
if (event instanceof NamingEvent) {
Cache cache = loadBalancerCacheManager.getCache(CachingServiceInstanceListSupplier.SERVICE_INSTANCE_CACHE_NAME);
if(cache!=null){
NamingEvent namingEvent = ((NamingEvent) event);
String serviceName = namingEvent.getServiceName();
List<Instance> instances = namingEvent.getInstances();
cache.put(serviceName, NacosServiceDiscovery.hostToServiceInstanceList(instances,serviceName));
}
}
}catch (Exception e){
e.printStackTrace();
}
}
public MyNacosEventListener(LoadBalancerCacheManager loadBalancerCacheManager) {
this.loadBalancerCacheManager = loadBalancerCacheManager;
}
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
/**
* spring工具类
*/
@Slf4j
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
private static ApplicationContext applicationContext = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextHolder.applicationContext = applicationContext;
}
public static <T> T getBean(Class<T> requiredType) {
return applicationContext.getBean(requiredType);
}
public static void clearHolder() {
if (log.isDebugEnabled()) {
log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
}
applicationContext = null;
}
@Override
public void destroy() {
SpringContextHolder.clearHolder();
}
}
配置好重启网关服务,naocs管理端修改服务下线状态,发现断点已经进入监听类即完成配置