欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

springcloud gateway动态路由配置

程序员文章站 2022-06-13 15:47:10
...

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

一.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<RouteDefinition> getRouteDefinitions() {
        List<RouteDefinition> routeDefinitions = new ArrayList<>();
        //将map中的路由加到路由配置中
        Map<String, RouteDefinition> routeMap= RouteConfig.getRouteMap();
        routeMap.forEach((key, route)->{routeDefinitions.add(route);});
        return Flux.fromIterable(routeDefinitions);
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return null;
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return null;
    }
}

2.路由配置map

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

    //存放路由
    private static Map<String, RouteDefinition> RouteMap=new HashMap<String,RouteDefinition>();

    public static void setRouteMap(Map<String, RouteDefinition> 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<String, RouteDefinition> 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<String, Object> 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<Object, Object> 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