此方法成功后以此类推可以获取监听nacos上的所有配置
spring cloud 版本:Hoxton.SR3
spring boot 版本:2.2.5.RELEASE
spring cloud alibaba版本:2.2.1.RELEASE
–其他版本对应可以自行相关文档对应(手动滑稽)
bootstrap.yml的内容
spring:
application:
name: gateway-service
cloud:
gateway:
discovery:
locator:
lower-case-service-id: true #忽略服务大小写
enabled: true #动态创建路由
nacos:
discovery:
server-addr: 10.165.12.109:8848
enabled: true
config:
file-extension: yaml
server-addr: 10.165.12.109:8848
server:
port: 1111
application.yml的内容
polo:
nacos:
whiteApiName : "whiteApi" #这个地方不需要用
whiteIpName : "whiteIp" #这个地方不需要用
gateway:
dateId: "gateway-service-route"
group: "DEFAULT_GROUP"
pom.xml的内容
org.springframework.boot
spring-boot-starter-webflux
org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-starter-gateway
org.springframework.boot
spring-boot-starter-validation
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
com.alibaba
fastjson
org.projectlombok
lombok
@Configuration
public class GatewayConfig {
public static final long DEFAULT_TIMEOUT = 30000;
public static String GATEWAY_CONFIG_DATA_ID;
public static String GATEWAY_CONFIG_GROUP;
public static String NACOS_SERVER_ADDR;
@Value("${spring.cloud.nacos.discovery.server-addr}")
public void setNacosServerAddr(String nacosServerAddr){
NACOS_SERVER_ADDR = nacosServerAddr;
}
@Value("${polo.gateway.dateId}")
public void setGatewayConfigDataId(String gatewayConfigDataId){
GATEWAY_CONFIG_DATA_ID = gatewayConfigDataId;
}
@Value("${polo.gateway.group}")
public void setGatewayConfigGroup(String gatewayConfigGroup){
GATEWAY_CONFIG_GROUP = gatewayConfigGroup;
}
}
@Slf4j
@ConditionalOnProperty(value = "spring.cloud.nacos.config.enabled", matchIfMissing = true)
@Component
public class DynamicRouteListener {
ConfigService configService;
@Autowired
RouteDefinitionWriter routeDefinitionWriter;
@Autowired
ApplicationEventPublisher applicationEventPublisher;
@EventListener(ApplicationReadyEvent.class)
public void createListener(){
if ((configService =initConfigService()) == null){
log.error("【configService】为空");
return;
}
try {
//通过configService使用配置id和group拿到路由文本以及编写监听器事件
String route =configService.getConfigAndSignListener(GatewayConfig.GATEWAY_CONFIG_DATA_ID,GatewayConfig.GATEWAY_CONFIG_GROUP,10000, new Listener() {
@Override
public Executor getExecutor() {
return null;
}
//监听器监听到配置更新
@Override
public void receiveConfigInfo(String s) {
log.info("【路由更新】监听到路由更新:{}", s);
List list = JsonUtils.toList(s, RouteDefinition.class);
list.forEach(definition->{
//监听器更新
updateDefinition(definition);
});
}
});
log.info("现有路由:{}",route);
//拿到目前的路由并发布
JsonUtils.toList(route,RouteDefinition.class).forEach( f ->{
updateDefinition(f);
});
} catch (NacosException e) {
e.printStackTrace();
}
}
private void updateDefinition(RouteDefinition routeDefinition){
//删除原路由
try {
routeDefinitionWriter.delete(Mono.just(routeDefinition.getId()));
} catch (Exception e) {
log.error("删除原路由失败");
}
//保存并发布新路由
try {
routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
} catch (Exception e) {
log.error("发布路由失败");
e.printStackTrace();
}
}
/**
* 初始化configService
* @return
*/
private ConfigService initConfigService(){
Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR,GatewayConfig.NACOS_SERVER_ADDR);
try {
return NacosFactory.createConfigService(properties);
} catch (NacosException e){
log.error("【ConfigService】初始化失败");
return null;
}
}
}
上面代码大概总结如下:
/**
* 动态路由:
* 1.初始化ConfigService(当然也可以创建一个配置类然后再自动注入)
* 2.通过初始化configService.getConfigAndSignListener(id,group,timeout,listener)拿到当前配置和监听器(@EventListener(ApplicationReadyEvent.class(事件源.class)))
* 2.1。监听器监听nacos配置,并转化为RouteDefinition,并更新发布
* 3.拿到当前当前文本路由进行发布更新
*/
上文中有个工具类也贴在下面
@Slf4j
public class JsonUtils {
private static ObjectMapper mapper = new ObjectMapper();
public static List toList(String jsonData, Class beanType) {
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, beanType);
try {
return mapper.readValue(jsonData, javaType);
} catch (Exception e) {
log.warn("", e);
}
return new ArrayList();
}
}
启动类也要加上@Enabl
eDiscoveryClient用来连接nscos上注册发现
测试
1.启动nacos:本文用的window版本,在nacos bin目录下,startup.cmd -m standalone 启动,能够进入nacos网站地址说明启动成功
2.启动网关
2.1.1 启动官网时,将会自动注册nacos服务列表
2.1.2 由于我们添加了监听器,启动时就会首先去nacos读取相关配置(先得在nacos配置管理编写与咱们yml名字对应的配置文件),并发布(上面代码有体现)
打印的日志
nacos上面编写的配置(pattern参数多了一个/!)
可以看出和我们的配置一毛一样
配置类容贴上
[{
"id": "user-center",
"order": 0,
"predicates": [{
"args": {
"pattern": "user-center/**"
},
"name": "Path"
}],
"uri": "lb://user-center"
}]
在nacos修改配置并发布,看监听器能否监听并发布
控制成功监听到了
1.网关路由编写是json格式和名字对用RouteDefinition,不然一个字母的错误毁了一个小时
2.各个cloud boot alibaba 版本对应上