Johniya Blog
首页 博客 社区 问答 开发者 约米云盘 注册
springgateway动态路由配置
默凌 2024-07-09 17:08:29 北京 spring java 开发

在webflux环境下,spring-gateway从数据库读取路由配置,并且随着数据库修改,可以动态变化。

如果只实现从数据库中读取路由数据,只需要实现RouteDefinitionLocator接口或RouteDefinitionRepository接口即可。

RouteDefinitionRepository继承自RouteDefinitionLocator,用哪个没啥大区别

MyRouteDefinitionRepository.class

@Component
public class MyRouteDefinitionRepository implements RouteDefinitionLocator {

	public Flux<RouteDefinition> getRouteDefinitions() {
		// 从数据库中获取路由配置,并封装为RouteDefinition对象
	}
}

但是如果想要在数据库数据发生变化时,重新加载路由配置,就需要额外的操作。

GatewayAutoConfiguration类中,首先把所有的RouteDefinitionLocator实现类封装为一个RouteDefinitionLocator对象,并设为@Primary

然后再把刚才已经封装的RouteDefinitionLocator对象以及配置文件或其他途径获取的路由配置,加一起再次封装为RouteLocator对象。

然后再把所有的RouteLocator实现类一起封装成一个RouteLocator对象,并设为@Primary,这个RouteLocator对象具体的实现类是CachingRouteLocator

最后通过CachingRouteLocator类的getRouteDefinitions()方法获取最终的路由配置对象

GatewayAutoConfiguration.class

	@Bean
    @ConditionalOnMissingBean({RouteDefinitionRepository.class})
    public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() {
        return new InMemoryRouteDefinitionRepository();
    }

    @Bean
    @Primary
    public RouteDefinitionLocator routeDefinitionLocator(List<RouteDefinitionLocator> routeDefinitionLocators) {
        return new CompositeRouteDefinitionLocator(Flux.fromIterable(routeDefinitionLocators));
    }

    @Bean
    public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties, List<GatewayFilterFactory> GatewayFilters, List<RoutePredicateFactory> predicates, RouteDefinitionLocator routeDefinitionLocator, @Qualifier("webFluxConversionService") ConversionService conversionService) {
        return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, GatewayFilters, properties, conversionService);
    }

    @Bean
    @Primary
    public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
        return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
    }

CachingRouteDefinitionLocator中可以看到,最终返回的是成员变量this.routeDefinitions,但是this.routeDefinitions在构造方法初始化时被赋予了一个响应式的结果

所以this.routeDefinitions的具体值是一个函数,该函数不会在构造方法内执行。

这个缓存函数的参数为上面封装的一个@PrimaryRouteLocator对象,当前this.cache为空时,调用RouteLocatorgetRouteDefinitions方法,这时才调用了我们实现的数据库方法。

于是该类提供了一个refresh方法,用来清空缓存。

该类监听了RefreshRoutesEvent事件,当产生事件时,即调用refresh方法。

CachingRouteDefinitionLocator.class

package org.springframework.cloud.gateway.route;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.context.ApplicationListener;
import reactor.cache.CacheFlux;
import reactor.cache.CacheFlux.FluxCacheBuilderMapMiss;
import reactor.core.publisher.Flux;

public class CachingRouteDefinitionLocator implements RouteDefinitionLocator, ApplicationListener<RefreshRoutesEvent> {
    private final RouteDefinitionLocator delegate;
    private final Flux<RouteDefinition> routeDefinitions;
    private final Map<String, List> cache = new HashMap();

    public CachingRouteDefinitionLocator(RouteDefinitionLocator delegate) {
        this.delegate = delegate;
        FluxCacheBuilderMapMiss var10001 = CacheFlux.lookup(this.cache, "routeDefs", RouteDefinition.class);
        RouteDefinitionLocator var10002 = this.delegate;
        var10002.getClass();
        this.routeDefinitions = var10001.onCacheMissResume(var10002::getRouteDefinitions);
    }

    public Flux<RouteDefinition> getRouteDefinitions() {
        return this.routeDefinitions;
    }

    public Flux<RouteDefinition> refresh() {
        this.cache.clear();
        return this.routeDefinitions;
    }

    public void onApplicationEvent(RefreshRoutesEvent event) {
        this.refresh();
    }

    /** @deprecated */
    @Deprecated
    void handleRefresh() {
        this.refresh();
    }
}

于是我们可以创建一个事件发布器,来发布RefreshRoutesEvent事件,用来通知清除缓存。

RouteRefreshEventPublisher.class

@Component
public class RouteRefreshEventPublisher {

    @Autowired
    private ApplicationEventPublisher publisher;

    public void publishRefreshEvent() {
        publisher.publishEvent(new RefreshRoutesEvent(this));
    }
}

最后,我们在数据库对应表增删改的时候,发布事件,等再次发生http请求时,即可重新加载路由配置。

云服务器 免费试用 一键搭建个人网站 现在购买,领取免费顶级域名 糯米云
5
1
0
21
评论 0
@Johniya.top