spring cloud gateway搭配nacos动态更新路由

第一步,获取NamingService

获取NamingService

@Configuration
public class InitConfiguration {
	
	@Bean
	public NamingService namingService(NacosServiceManager nacosServiceManager, NacosDiscoveryProperties nacosDiscoveryProperties) {
		return nacosServiceManager.getNamingService(nacosDiscoveryProperties.getNacosProperties());
	}
	
}

第二步,自定义事件

自定义事件是为了解耦,订阅NamingService,当有instance发送变化时,利用applicationContext发布事件

import org.springframework.context.ApplicationContext;
import org.springframework.context.event.ApplicationContextEvent;
import org.springframework.stereotype.Component;

@Component
public class NacosInstanceChangeEvent extends ApplicationContextEvent {
	/**
	 * 
	 */
	private static final long serialVersionUID = -5198386861491058274L;

	public NacosInstanceChangeEvent(ApplicationContext source) {
		super(source);
	}
}

第三步,利用namingService添加nacos事件订阅,然后发布第二步的事件

	@PostConstruct
    public void init() {
    	initNacosSubscribe(namingService);
    }
    
	/**
	 * 	初始化nacos中的instance的变化监听
	 * @param namingService
	 */
    public void initNacosSubscribe(NamingService namingService) {
    	try {
    		//需要监听的servicename
			namingService.subscribe("servicename", event -> {
				if (event instanceof NamingEvent) {
					String serviceName = ((NamingEvent) event).getServiceName();
					List<Instance> insteanceList = ((NamingEvent) event).getInstances();
					LOG.info("实例发生变更:ServiceName=" + serviceName + ",instanceList=" + insteanceList);
					//发布事件
					applicationContext.publishEvent(new NacosInstanceChangeEvent(applicationContext));
				}
			});
		} catch (NacosException e) {
			e.printStackTrace();
		}
    }

第四步,监听第三步发送的事件

@Component
public class NacosInstanceChangeListener implements ApplicationListener<NacosInstanceChangeEvent> ,ApplicationEventPublisherAware {
	private static final Logger LOG = LoggerFactory.getLogger(NacosInstanceChangeListener.class);
	
	@Autowired
    private RouteDefinitionWriter routeDefinitionWriter;
	
	@Autowired
	private RouteLocator routeLocator;
	
	@Autowired
	private DiscoveryClient discoveryClient;
	
    private ApplicationEventPublisher publisher;
    
    
    
	@Override
	public void onApplicationEvent(NacosInstanceChangeEvent event) {
		LOG.info("收到NacosInstanceChangeEvent,准备更新路由");
		//重新发布路由
		//1、获取当前所有路由
		Flux<Route> routes = routeLocator.getRoutes();
		//更新路由
		updateUploadClientRoute(routes);
	}

	@Override
	public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
		this.publisher = applicationEventPublisher;
	}
	
	/**
	 * 	增加路由
	 * @param definition
	 * @return
	 */
    public String add(RouteDefinition definition) {
        routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        return "success";
    }
	
	/**
	 * 	更新路由
	 * @param definition
	 * @return
	 */
    public String update(RouteDefinition definition) {
        try {
            delete(definition.getId());
        } catch (Exception e) {
            return "update fail,not find route  routeId: "+definition.getId();
        }
        try {
            routeDefinitionWriter.save(Mono.just(definition)).subscribe();
            this.publisher.publishEvent(new RefreshRoutesEvent(this));
            return "success";
        } catch (Exception e) {
            return "update route  fail";
        }
    }
    
    /**
     * 	删除路由
     * @param id
     * @return
     */
    public Mono<ResponseEntity<Object>> delete(String id) {
        return this.routeDefinitionWriter.delete(Mono.just(id)).then(Mono.defer(() -> {
            return Mono.just(ResponseEntity.ok().build());
        })).onErrorResume((t) -> {
            return t instanceof NotFoundException;
        }, (t) -> {
            return Mono.just(ResponseEntity.notFound().build());
        });
    }

    /**
     * 	更新UploadClient路由
     * @param routes
     */
    public void updateUploadClientRoute(Flux<Route> routes) {
    	//获取需要删除的路由列表,这里以路由id的固定前缀获取
    	Flux<Route> uploadClientRoutes = routes.filter(route -> route.getId().startsWith("xxxx,这里为路由的id"));
		//2、删除满足条件的所有路由
		uploadClientRoutes.subscribe(route -> {
			LOG.info("删除xxxxxx路由");
            //调用删除
			String routeId = route.getId();
			delete(routeId);
        }, error -> {
        	LOG.error("更新路由出错:",error.getCause());
        }, () -> {
        	//3、新加新的路由,获取当前nacos中的instance信息
        	List<ServiceInstance> instances = discoveryClient.getInstances("ServiceName");
        	
        	for (ServiceInstance instance : instances) {
        		Map<String, String> metadata = instance.getMetadata();
        		String uploadClientId = metadata.get("clientId");
        		//路由
        		RouteDefinition routeDefinition = new RouteDefinition();
        		//设置路由id
        		routeDefinition.setId("xxxxx-" + uploadClientId);
        		routeDefinition.setUri(instance.getUri());
        		//设置断言
        		List<PredicateDefinition> predicateDefinitionList=new ArrayList<>();
        		PredicateDefinition predicateDefinition = new PredicateDefinition();
        		//断言类型,Header,Before等,取值来自RouteDefinitionRouteLocator.predicates
        		predicateDefinition.setName("Header");
        		//断言参数,比如满足header中的clientid为uploadClientId的
        		predicateDefinition.addArg("header", "clientId," + uploadClientId);
        		//可以有多个断言
        		predicateDefinitionList.add(predicateDefinition);
        		routeDefinition.setPredicates(predicateDefinitionList);
        		add(routeDefinition);
			}
        	
        	//发起路由更新事件
        	this.publisher.publishEvent(new RefreshRoutesEvent(this));
        });
    }
    
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值