Gateway整合

引入依赖

  1. <!--GateWay 网关-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-gateway</artifactId>
  5. </dependency>
  6. <!--引入webflux-->
  7. <dependency>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-webflux</artifactId>
  10. <exclusions><!-- 去掉springboot默认配置 -->
  11. <exclusion>
  12. <groupId>org.springframework.boot</groupId>
  13. <artifactId>spring-boot-starter-logging</artifactId>
  14. </exclusion>
  15. </exclusions>
  16. </dependency>

配置项

spring
  cloud
    gateway:
      discovery:
        locator:
          enabled: true

整合nacos实现动态路由配置

nacos路由配置文件监听器

package com.isoftstone.cloud.config.nacos.dynamic.route;


import com.alibaba.nacos.api.config.ConfigFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Properties;
import java.util.concurrent.Executor;

@Component
public class DynamicRouteListener {

    private String dataId = "Dynamic-gateway-routes";

    private String group = "DEFAULT_GROUP";

    @Value("${spring.cloud.nacos.config.server-addr}")
    private String serverAddr;

    @Value("${spring.cloud.nacos.config.username}")
    private String username;

    @Value("${spring.cloud.nacos.config.password}")
    private String password;

    @Autowired
    DynamicRouteOperator routeOperator;

    @PostConstruct
    public void dynamicRouteByNacosListener() throws NacosException {
        Properties properties = new Properties();
        properties.put("serverAddr", serverAddr);
        properties.put("username",username);
        properties.put("password",password);
        ConfigService configService = ConfigFactory.createConfigService(properties);
        // 添加监听,nacos上的配置变更后会执行
        configService.addListener(dataId, group, new Listener() {
            public void receiveConfigInfo(String configInfo) {
                // 解析和处理都交给RouteOperator完成
                routeOperator.refreshAll(configInfo);
            }
            public Executor getExecutor() {
                return null;
            }
        });
        // 获取当前的配置
        String initConfig = configService.getConfig(dataId, group, 5000);
        // 立即更新
        routeOperator.refreshAll(initConfig);
    }
}

根据路由配置文件进行路由缓存管理

package com.isoftstone.cloud.config.nacos.dynamic.route;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
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.util.StringUtils;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;

/**
 * 动态路由
 */
public class DynamicRouteOperator {

    private ObjectMapper objectMapper;

    private RouteDefinitionWriter routeDefinitionWriter;

    private ApplicationEventPublisher applicationEventPublisher;

    private static final List<String> routeList = new ArrayList<>();

    public DynamicRouteOperator(ObjectMapper objectMapper, RouteDefinitionWriter routeDefinitionWriter, ApplicationEventPublisher applicationEventPublisher) {
        this.objectMapper = objectMapper;
        this.routeDefinitionWriter = routeDefinitionWriter;
        this.applicationEventPublisher = applicationEventPublisher;
    }

    /**
     * 清理集合中的所有路由,并清空集合
     */
    private void clear() {
        // 全部调用API清理掉
        routeList.stream().forEach(id -> routeDefinitionWriter.delete(Mono.just(id)).subscribe());
        // 清空集合
        routeList.clear();
    }

    /**
     * 新增路由
     * @param routeDefinitions
     */
    private void add(List<RouteDefinition> routeDefinitions) {

        try {
            routeDefinitions.stream().forEach(routeDefinition -> {
                routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
                routeList.add(routeDefinition.getId());
            });
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

    /**
     * 发布进程内通知,更新路由
     */
    private void publish() {
        applicationEventPublisher.publishEvent(new RefreshRoutesEvent(routeDefinitionWriter));
    }

    /**
     * 更新所有路由信息
     * @param configStr
     */
    public void refreshAll(String configStr) {
        // 无效字符串不处理
        if (!StringUtils.hasText(configStr)) {
            return;
        }

        // 用Jackson反序列化
        List<RouteDefinition> routeDefinitions = null;
        try {
            routeDefinitions = objectMapper.readValue(configStr, new TypeReference<List<RouteDefinition>>(){});
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        // 如果等于null,表示反序列化失败,立即返回
        if (null==routeDefinitions) {
            return;
        }
        // 清理掉当前所有路由
        clear();
        // 添加最新路由
        add(routeDefinitions);
        // 通过应用内消息的方式发布
        publish();

    }
}

动态路由配置类生效

package com.isoftstone.cloud.config.nacos.dynamic.route;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 动态路由
 */
@Configuration
public class DynamicRouteConfig {
    @Bean
    public DynamicRouteOperator routeOperator(ObjectMapper objectMapper,
                                              RouteDefinitionWriter routeDefinitionWriter,
                                              ApplicationEventPublisher applicationEventPublisher) {

        return new DynamicRouteOperator(objectMapper,
                routeDefinitionWriter,
                applicationEventPublisher);
    }
}

nacos控制台

image.png

配置内容

[
    {
        "id": "insurance-customer",
        "uri": "lb://insurance-customer",
        "predicates":[
            {
                "name": "Path",
                "args": {
                    "pattern": "/customer/**"
                }
            }
        ]
    },
    {
        "id": "insurance-auth",
        "uri": "lb://insurance-auth",
        "predicates":[
            {
                "name": "Path",
                "args": {
                    "pattern": "/auth/**"
                }
            }
        ]
    }
]