SpringBoot+Nacos+Gateway动态路由
前言:
动态路由: 可见标题 架构选择nacos作为服务注册,GateWay作为网关两者都是ali。那nacos咱们都知道可作为配置中心
来使用且可动态,那做一个动态路由我觉得还是有些必要性的,不至于每次增加路由都要重新部署服务。之前写过一篇动态路由的文章,但那个可能使用的cloud,springboot版本低 以至于到现在的版本监听不到,而且那个是json版本。所以写下这篇文章。
‘新版’动态路由(yaml格式)
版本信息:springboot:2.2.2.RELEASE------com.alibaba.cloud: 2.2.4.RELEASE-----org.springframework.cloud:Hoxton.RELEASE
上代码
@Data
@Component
@ConfigurationProperties(prefix = "broad.dynamic.route")//yml配置信息,下文给出
@ConditionalOnBean(DynamicRouteConfiguration.class)
public class DynamicRouteProperties {
/**
* nacos 配置管理 dataId
*/
private String dataId;
/**
* nacos 配置管理 group
*/
private String group;
/**
* nacos 服务地址
*/
private String ipAddr;
/**
* 启动动态路由的标志,默认关闭
*/
private boolean enabled = false;
}
DynamicRouteConfiguration
@Configuration
@ConditionalOnProperty(name = "broad.dynamic.route.enabled", matchIfMissing = true)
public class DynamicRouteConfiguration implements ApplicationEventPublisherAware {
Logger log= LoggerFactory.getLogger(DynamicRouteConfiguration.class);
//namespace名称
private final static String NAMESPACE="8359a8d9-03ab-4574-9627-9456351c0c01";
//nacos账号密码
private final static String USERNAME_PASSWORD="nacos";
//截取字符
private final static String REPLACE="routes:";
private DynamicRouteProperties bean;
private RouteDefinitionWriter writer;
private ApplicationEventPublisher publisher;
public DynamicRouteConfiguration(DynamicRouteProperties bean, RouteDefinitionWriter writer, ApplicationEventPublisher publisher) {
this.bean = bean;
this.writer = writer;
this.publisher = publisher;
}
@PostConstruct
private void init() {
Assert.notNull(bean.getDataId(), "broad.dynamic.route.dataId null异常");
Assert.notNull(bean.getGroup(), "broad.dynamic.route.group is null异常");
Assert.notNull(bean.getIpAddr(), "broad.dynamic.route.ipAddr is null异常");
dynamicRouteByNacosListener();
}
private void dynamicRouteByNacosListener() {
try {
Properties properties = new Properties();
properties.put(PropertyKeyConst.NAMESPACE, NAMESPACE);
properties.put(PropertyKeyConst.SERVER_ADDR, bean.getIpAddr());
properties.put("username",USERNAME_PASSWORD);
properties.put("password",USERNAME_PASSWORD);
ConfigService configService = NacosFactory.createConfigService(properties);
String content = configService.getConfigAndSignListener(
bean.getDataId(),
bean.getGroup(),
5000,
new AbstractListener() {
@Override
public void receiveConfigInfo(String configInfo) {
updateConfig(configInfo);
}
});
updateConfig(content);
} catch (NacosException e) {
log.error("nacos 获取动态路由配置和监听异常", e);
}
}
private void updateConfig(String content) {
String contentReally=replaceContext(content);
log.info("nacos 动态路由更新: {}", contentReally);
try {
getRouteDefinitions(contentReally).forEach(routeDefinition -> {
log.info("动态路由配置: {}", routeDefinition);
writer.delete(Mono.just(routeDefinition.getId()));
writer.save(Mono.just(routeDefinition)).subscribe();
publisher.publishEvent(new RefreshRoutesEvent(this));
});
} catch (Exception e) {
log.error("更新动态路由配置异常: ", e);
}
}
/**
* 因在nacos配置路由携带 spring前缀,会导致yaml解析失败,因此需截取
* @return
*/
private String replaceContext(String content){
String contentDelete=content.replaceAll("\r|\n", "").substring(0, content.indexOf(REPLACE)+1);
String contentReally=content.substring(contentDelete.length()+7, content.length());
return contentReally;
}
/**
* yaml转换
* @param content
* @return
*/
private List<RouteDefinition> getRouteDefinitions(String content) {
return JSON.parseArray(JSON.toJSONString(
YamlHelper.getInstance().load(content)
), RouteDefinition.class);
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
}
yaml
public abstract class YamlHelper {
private YamlHelper() {}
public static Yaml getInstance() {
return InnerClass.YAML;
}
private static class InnerClass {
private static final Yaml YAML = new Yaml();
}
}
解释:
第1:
但是在转换之前字符串content格式不正确,因为我在nacos配置的还有前缀 如下图:
(但好像不加这个前缀也可以,这个我忘试了 大家可以自测一下)
所以我需要把这些前缀去掉。因此有了去除前缀的方法replaceContext
第2:
第三:这是yml配置的参数
都是干货呦,大家有什么不懂可以评论区问我,有写的不对的大家指正,感谢!