🍃【SpringCloud 基础使用】Nacos 与 Gateway 实现动态路由
每日一句
人生就是一种追求,一种努力,一种期盼。渴望着把梦想变成现实,将虚幻化为真实。生活,因梦而美好;人生,因梦而苦闷。然而,再难的道,也有尽头;再长的路,也有出口,坚持就会有光明。
动态网关配置
一. Maven 依赖
<!-- 网关依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- nacos注册中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- nacos配置中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- 简化set/get -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 支持yml、properties文件提示 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- yaml解析包 -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
二.创建配置提示
1、DynamicRouteProperties 类
package com.ksaas.cloud.gateway.config;
import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 包含 动态路由配置 的属性
*
* @author kylin
* @see DynamicRouteConfiguration
* @since 1.0.0
*/
@Data
@Component
@ConfigurationProperties(prefix = "ksaas.dynamic.route")
@ConditionalOnBean(DynamicRouteConfiguration.class)
public class DynamicRouteProperties {
/**
* nacos 配置管理 dataId
*/
private String dataId;
/**
* nacos 配置管理 group
*/
private String group;
/**
* nacos 服务地址
*/
private String ipAddr;
/**
* 启动动态路由的标志,默认关闭
*/
private boolean enabled = false;
}
2、创建 yml 参数规则
在 resources/META-INF 下创建 spring-configuration-metadata.json
{
"groups": [
{
"sourceType": "com.ksaas.cloud.gateway.config.DynamicRouteConfiguration",
"name": "动态路由配置属性",
"type": "com.ksaas.cloud.gateway.config.DynamicRouteConfiguration"
}
],
"hints": [
{
"name": "ksaas.dynamic.route.enabled",
"values": [
{
"value": true
},
{
"value": false
}
]
}
],
"properties": [
{
"sourceType": "com.ksaas.cloud.gateway.config.DynamicRouteConfiguration",
"name": "ksaas.dynamic.route.dataId",
"type": "java.lang.String",
"desc": "dataId specified in Nacos configuration management"
},
{
"sourceType": "com.ksaas.cloud.gateway.config.DynamicRouteConfiguration",
"name": "ksaas.dynamic.route.group",
"type": "java.lang.String",
"desc": "group specified in Nacos configuration management"
},
{
"sourceType": "com.ksaas.cloud.gateway.config.DynamicRouteConfiguration",
"name": "ksaas.dynamic.route.ipAddr",
"type": "java.lang.String",
"desc": "nacos host address"
},
{
"sourceType": "com.ksaas.cloud.gateway.config.DynamicRouteConfiguration",
"name": "ksaas.dynamic.route.enabled",
"type": "java.lang.Boolean",
"desc": "Flag that enables dynamic route"
}
]
}
三.配置动态路由拉取配置类
1. yaml 读取工具
package com.ksaas.cloud.gateway.util;
import org.yaml.snakeyaml.Yaml;
/**
* Yaml 工具
*
* @author kylin
*/
public abstract class YamlHelper {
private YamlHelper() {}
public static Yaml getInstance() {
return InnerClass.YAML;
}
private static class InnerClass {
private static final Yaml YAML = new Yaml();
}
}
2.configuration 类
package com.ksaas.cloud.gateway.config;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.AbstractListener;
import com.alibaba.nacos.api.exception.NacosException;
import com.ksaas.cloud.gateway.util.YamlHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.Assert;
import reactor.core.publisher.Mono;
import javax.annotation.PostConstruct;
import java.util.List;
/**
* 动态路由配置
*
* @author kylin
* @see route\example.yml 动态路由yml内容格式参考
* @see DynamicRouteProperties 动态路由参数配置说明
* @since 1.0.0
*/
@Slf4j
@Configuration
@ConditionalOnProperty(name = "ksaas.dynamic.route.enabled", matchIfMissing = true)
public class DynamicRouteConfiguration {
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(), "ksaas.dynamic.route.dataId null异常");
Assert.notNull(bean.getGroup(), "ksaas.dynamic.route.group is null异常");
Assert.notNull(bean.getIpAddr(), "ksaas.dynamic.route.ipAddr is null异常");
dynamicRouteByNacosListener();
}
private void dynamicRouteByNacosListener() {
try {
ConfigService configService = NacosFactory.createConfigService(bean.getIpAddr());
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) {
log.info("nacos 动态路由更新: {}", content);
try {
getRouteDefinitions(content).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);
}
}
private List<RouteDefinition> getRouteDefinitions(String content) {
// 如果文件是json,这里则直接把内容转会为json即可
return JSON.parseArray(JSON.toJSONString(
YamlHelper.getInstance().load(content)
), RouteDefinition.class);
}
}
四.配置 bootstrap.yml
nacos 2.2.0 及以下版本配置文件必须是 bootstrap 级别,不然只会找 localhost:8848 地址
server:
port: 9000
spring:
application:
# 应用名称
name: spring-gateway
cloud:
# 使用 Naoos 作为服务注册发现、配置中心
nacos:
server-addr: 192.168.1.150:8848
# 路由网关配置
gateway:
# 设置与服务注册发现组件结合,这样可以采用服务名的路由策略
discovery:
locator:
enabled: true
# 自定义动态路由配置,对应nacos配置列表参数
ksaas:
dynamic:
route:
dataId: gateway_dynamic_route_config
group: refresh_gateway_dynamic_route_config
ipAddr: ${spring.cloud.nacos.server-addr}
enabled: true
# 配置日志级别,方别调试
logging:
level:
org.springframework.cloud.gateway: debug
五. 创建规则
直接在 nacos 配置中心,创建即可,dataId 和 group 创建对应的 yml 文件即可,想做成 json,可以直接把下面内容去网上转换位 json 即可
- id: route1
filters:
- args:
parts: 1
name: StripPrefix
predicates:
- args:
pattern: /consumer-h/**
name: Path
uri: lb://consumer-h
- id: route2
filters:
- args:
parts: 1
name: StripPrefix
predicates:
- args:
pattern: /lilei/**
name: Path
uri: lb://nacos-test
- id: route3
filters:
- args:
parts: 1
name: StripPrefix
predicates:
- args:
pattern: /lilei4/**
name: Path
uri: https://www.baidu.com/
补充文件说明:
如果服务名和路由相同时
可不用配置动态路由,nacos 会自动做好路由
需要配置:spring.cloud.gateway.discovery.locator.enabled=true
如果服务名和路由不同时
需要自己在 nacos 配置管理创建一个 yml 格式的配置,创建时的参数根据自己的配置设定来创建{@link DynamicRouteConfigBean}
动态路由 yml 配置文件说明
id:采用自定义路由 ID(有固定用法,不同的 id 有不同的功能,详见:https://cloud.spring.io/spring-cloud-gateway/2.0.x/single/spring-cloud-gateway.html#gateway-route-filters)
filters:url 过滤器,例如添加请求参数,删除前缀等,参考接口:
GatewayFilterFactory
predicates:翻译过来是“谓词”的意思,必须,主要作用是匹配用户的请求,有很多种用法,参考接口:
GatewayPredicate
uri:采用 LoadBalanceClient 方式请求,以 lb:// 开头,后面的是注册在 Nacos 上的服务名
gateway:
设置与服务注册发现组件结合,这样可以采用服务名的路由策略
discovery:
locator:
enabled: true
版权声明: 本文为 InfoQ 作者【李浩宇/Alex】的原创文章。
原文链接:【http://xie.infoq.cn/article/157f97b7064bae8e00afc1de7】。文章转载请联系作者。
李浩宇/Alex
我们始于迷惘,终于更高水平的迷惘。 2020.03.25 加入
🏆 【酷爱计算机技术、醉心开发编程、喜爱健身运动、热衷悬疑推理的”极客狂人“】 🏅 【Java技术领域,MySQL技术领域,APM全链路追踪技术及微服务、分布式方向的技术体系等】 🤝未来我们希望可以共同进步🤝
评论