You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Spring WebFlux中动态选择同一请求对应的控制器?

实现Spring WebFlux动态路由权重分配的方案

在Spring WebFlux中实现基于自定义规则(如权重比例)的动态路由,可以通过自定义HandlerFunction结合可动态调整的配置来实现,核心思路是在统一路由入口处根据规则选择目标处理器,以下是具体实现步骤:

1. 定义动态权重配置类

创建线程安全的配置类,存储并允许修改控制器A、B的权重比例,适配WebFlux异步场景的并发需求:

import java.util.concurrent.atomic.AtomicReference;
import org.springframework.stereotype.Component;

@Component
public class RouteWeightConfig {
    // 数组存储[控制器A权重, 控制器B权重],总和建议设为100方便计算
    private final AtomicReference<int[]> weightRef = new AtomicReference<>(new int[]{60, 40});

    public int[] getWeights() {
        return weightRef.get();
    }

    public void updateWeights(int weightA, int weightB) {
        if (weightA < 0 || weightB < 0 || weightA + weightB != 100) {
            throw new IllegalArgumentException("权重必须非负且总和为100");
        }
        weightRef.set(new int[]{weightA, weightB});
    }
}

2. 实现动态路由转发的HandlerFunction

编写自定义HandlerFunction,注入权重配置和两个目标控制器的Handler,在请求处理时根据权重随机选择执行逻辑:

import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import java.util.concurrent.ThreadLocalRandom;

@Component
public class DynamicRouteHandler implements HandlerFunction<ServerResponse> {
    private final RouteWeightConfig weightConfig;
    private final HandlerFunction<ServerResponse> controllerAHandler;
    private final HandlerFunction<ServerResponse> controllerBHandler;

    // 构造注入两个目标控制器的HandlerFunction
    public DynamicRouteHandler(RouteWeightConfig weightConfig,
                               HandlerFunction<ServerResponse> controllerAHandler,
                               HandlerFunction<ServerResponse> controllerBHandler) {
        this.weightConfig = weightConfig;
        this.controllerAHandler = controllerAHandler;
        this.controllerBHandler = controllerBHandler;
    }

    @Override
    public Mono<ServerResponse> handle(ServerRequest request) {
        int[] weights = weightConfig.getWeights();
        int random = ThreadLocalRandom.current().nextInt(100);
        // 根据随机数区间判断执行哪个控制器
        if (random < weights[0]) {
            return controllerAHandler.handle(request);
        } else {
            return controllerBHandler.handle(request);
        }
    }
}

3. 注册路由规则

在RouterFunctions配置中,将/v1/xyz路径绑定到自定义的DynamicRouteHandler:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;

@Configuration
public class RouterConfig {

    @Bean
    public RouterFunction<ServerResponse> dynamicRoute(DynamicRouteHandler dynamicRouteHandler) {
        return RouterFunctions.route()
                .GET("/v1/xyz", dynamicRouteHandler)
                .POST("/v1/xyz", dynamicRouteHandler)
                .build();
    }

    // 定义控制器A的处理逻辑
    @Bean
    public HandlerFunction<ServerResponse> controllerAHandler() {
        return request -> ServerResponse.ok().bodyValue("Response from Controller A");
    }

    // 定义控制器B的处理逻辑
    @Bean
    public HandlerFunction<ServerResponse> controllerBHandler() {
        return request -> ServerResponse.ok().bodyValue("Response from Controller B");
    }
}

4. 提供权重动态调整接口

添加接口用于运行时修改权重比例,无需重启服务:

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class WeightAdjustController {
    private final RouteWeightConfig weightConfig;

    public WeightAdjustController(RouteWeightConfig weightConfig) {
        this.weightConfig = weightConfig;
    }

    @PostMapping("/adjust-weight")
    public String adjustWeight(@RequestParam int weightA, @RequestParam int weightB) {
        try {
            weightConfig.updateWeights(weightA, weightB);
            return "权重已更新:控制器A=" + weightA + "%,控制器B=" + weightB + "%";
        } catch (IllegalArgumentException e) {
            return "更新失败:" + e.getMessage();
        }
    }
}

关键注意事项

  • 线程安全:使用AtomicReference存储权重,避免并发修改导致的不一致问题;
  • 随机数生成:使用ThreadLocalRandom而非Random,在WebFlux异步场景下更高效且线程安全;
  • 扩展性:如果需要更复杂的路由规则(如基于用户标签、请求参数),只需修改DynamicRouteHandler的判断逻辑即可;
  • 参数校验:权重修改接口添加参数校验,避免非法配置导致路由异常。

内容的提问来源于stack exchange,提问作者Ray Chase

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 03:55:13