springcloud gateway动态路由配置

最近在给公司搭建的springcloud gateway框架,每次配置文件修改路由表信息之后就得重启或者重新发布,故采用动态路由的配置功能。看了网上的资料,决定采用redis缓存机制实现。
具体实现思路如下图,后台管理将路由配置缓存到redis中,gateway监听redis的修改事件,配置路由。
springcloud gateway动态路由配置_第1张图片

一.redis配置

首先先对redis进行配置,找到redis安装目录里的redis.conf文件(没有可以自己新建或者在启动redis服务时,选择其他配置文件),在配置文件中修改这个参数
notify-keyspace-events “Kg”
详细的可以参考
https://www.cnblogs.com/tangxuliang/p/10659439.html

二.Gateway路由配置

1.RouteDefinitionRepository接口
通过实现该接口,实现从 存储器 ( 例如,内存 / Redis / MySQL 等 )读取、保存、删除路由配置。因为每次url匹配到路由都会调用getRouteDefinitions,为了提高效率,路由配置不直接从redis获取,而是从map缓存中获取。

@Component
public class RedisRouteDefinitionRepository implements RouteDefinitionRepository {
    @Override
    public Flux getRouteDefinitions() {
        List routeDefinitions = new ArrayList<>();
        //将map中的路由加到路由配置中
        Map routeMap= RouteConfig.getRouteMap();
        routeMap.forEach((key, route)->{routeDefinitions.add(route);});
        return Flux.fromIterable(routeDefinitions);
    }

    @Override
    public Mono save(Mono route) {
        return null;
    }

    @Override
    public Mono delete(Mono routeId) {
        return null;
    }
}

2.路由配置map

public class RouteConfig {
    public static final String REDIS_ROUTE_SOURCE="gatewayroutes";

    //存放路由
    private static Map RouteMap=new HashMap();

    public static void setRouteMap(Map routeMap) {
        RouteMap = routeMap;
    }

    /**
     * 添加路由
     * @param key
     * @param route
     */
    public static void addRoute(String key, RouteDefinition route){
        RouteMap.put(key,route);
    }

    /**
     * 清空路由
     */
    public static void clearRoute(){
        RouteMap.clear();
    }
    public static Map getRouteMap() {
        return RouteMap;
    }
}

三.实现redis监听

1.监听容器
这里我把容器直接配置在了application类中,也可以新建一个类

@SpringBootApplication
public class GiCloudGateway_App
{
	public static void main(String[] args)
	{
		SpringApplication.run(GiCloudGateway_App.class, args);
	}
	/**
	 * 配置redis监听容器
	 * @param connectionFactory
	 * @return
	 */
	@Bean
	RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
		RedisMessageListenerContainer container = new RedisMessageListenerContainer();
		container.setConnectionFactory(connectionFactory);
		return container;
	}
}

2.创建监听器RedisMessageListener
该监听器继承KeyspaceEventMessageListener类,该类可以监听所有的键空间通知。
监听到redis中路由的修改后,将路由存到路由map缓存中,并调用publishEvent(new RefreshRoutesEvent(this)),触发RedisRouteDefinitionRepository的getRouteDefinitions方法

@Slf4j
@Component
public class RedisMessageListener extends KeyspaceEventMessageListener {
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private ApplicationEventPublisher publisher;

    public RedisMessageListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }
    @Override
    public void onMessage(Message message, byte[] pattern) {
        //监听redis的改变,若改变的值为GATEWAY_ROUTES,则更新路由map
        String changeKey = message.toString();
        try {
            if (changeKey.contains(RouteConfig.REDIS_ROUTE_SOURCE)) {
                //先清空路由
                log.info("清空路由");
                RouteConfig.clearRoute();
                //从redis中获取路由
                Map redisRouteMap = redisTemplate.opsForHash().entries(RouteConfig.REDIS_ROUTE_SOURCE);
                redisRouteMap.forEach((key, routeDefinition) -> {
                    RouteConfig.addRoute(key.toString(), JSON.parseObject(routeDefinition.toString(), RouteDefinition.class));
                });
                this.publisher.publishEvent(new RefreshRoutesEvent(this));
                log.info("路由重置成功");
            }
        } catch (Exception ex) {
            log.error("异常信息:", ex);
        }
    }
}

你可能感兴趣的:(springcloud)