🍃【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 过滤器,例如添加请求参数,删除前缀等,参考接口: - 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全链路追踪技术及微服务、分布式方向的技术体系等】 🤝未来我们希望可以共同进步🤝











 
    
评论