gateway集成nacos实现动态网关

1.将gateway注册至nacos

此方法成功后以此类推可以获取监听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的内容

<!--webflux反应式框架-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <!--监控系统健康-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!--gateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <!--服务配置-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--服务发现-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>


编写一个配置类用来读取目前配置文件yml的内容

@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;
    }
}

编写一个监听器用来获取监听nacos上面的配置文件,并且更新发布

@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<RouteDefinition> 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 <T> List<T> toList(String jsonData, Class<T> 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<T>();
   }
}

启动类也要加上@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 版本对应上

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值