Modifying Spring Cloud Gateway routes at runtime

3k views Asked by At

I would like to add or delete Spring Cloud Gateway routes at runtime while the server is running. I'm using the Fluent Java Routes API to initialize gateway routes. This is working perfectly.

However, now I'd like to modify, add, and delete routes while the Spring Cloud Gateway server is running. I can see that the RouteLocator contains my routes, but I see no methods to modify its contents.

Even though I see some ability to create new routes in the actuator, I need to use add them using Java code instead of REST calls. In my setup the RouteDefinitionRepository is empty, so I didn't see any way to use this in my use case.

Is it possible to modify routes at runtime using just Java code in Spring Cloud Gateway?

2

There are 2 answers

0
Robert On

Use Spring Integration instead. You can use the Java DSL to register and delete Integration Flows. https://docs.spring.io/spring-integration/docs/5.3.2.RELEASE/reference/html/dsl.html#java-dsl-runtime-flows

0
Ares91 On

I have done something similar to remove routes, to hide service from gateway. Try instanciating a custom RouteLocator like bellow:

@Configuration
public class RouteConfiguration implements CommandLineRunner {

    final Logger LOGGER = LoggerFactory.getLogger(RouteConfiguration.class);

    @Value("${route.ignore.service-ids}")
    private String[] ignoreServiceIds;

    @Override
    public void run(String... args) throws Exception {

        if(ignoreServiceIds != null){
            for(String s: ignoreServiceIds){
                LOGGER.info("ServiceID ignored: {}",s);
            }
        }
    }

    @Bean
    @Primary
    @ConditionalOnMissingBean(name = "cachedCompositeRouteLocator")
    public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {

        return new CachingRouteLocator(new CustomCompositeRouteLocator(Flux.fromIterable(routeLocators), ignoreServiceIds));
    }
}

and then apply filter:

public class CustomCompositeRouteLocator implements RouteLocator {

    private final Flux<RouteLocator> delegates;
    private List<String> ignoredServiceIds;

    public CustomCompositeRouteLocator(Flux<RouteLocator> delegates, String[] ignoreServiceIds) {
        this.delegates = delegates;

        if(ignoreServiceIds != null && ignoreServiceIds.length>0)
            this.ignoredServiceIds = List.of(ignoreServiceIds);
    }

    @Override
    public Flux<Route> getRoutes() {

        if(ignoredServiceIds == null || ignoredServiceIds.isEmpty())
            return this.delegates.flatMapSequential(RouteLocator::getRoutes);
        return this.delegates.flatMapSequential(RouteLocator::getRoutes).filter(p->!ignoredServiceIds.contains(p.getUri().getHost()));
    }
}

and in the application.yaml

...
route:
  ignore:
    service-ids: MY_IGNORED_SERVICE_ID
...