第一步,获取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));
});
}
}