🍃【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: 9000spring: 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 过滤器,例如添加请求参数,删除前缀等,参考接口:
GatewayFilterFactorypredicates:翻译过来是“谓词”的意思,必须,主要作用是匹配用户的请求,有很多种用法,参考接口:
GatewayPredicateuri:采用 LoadBalanceClient 方式请求,以 lb:// 开头,后面的是注册在 Nacos 上的服务名
gateway:
设置与服务注册发现组件结合,这样可以采用服务名的路由策略
discovery:
locator:
enabled: true
版权声明: 本文为 InfoQ 作者【李浩宇/Alex】的原创文章。
原文链接:【http://xie.infoq.cn/article/157f97b7064bae8e00afc1de7】。文章转载请联系作者。
李浩宇/Alex
我们始于迷惘,终于更高水平的迷惘。 2020.03.25 加入
🏆 【酷爱计算机技术、醉心开发编程、喜爱健身运动、热衷悬疑推理的”极客狂人“】 🏅 【Java技术领域,MySQL技术领域,APM全链路追踪技术及微服务、分布式方向的技术体系等】 🤝未来我们希望可以共同进步🤝











评论