在Spring MVC项目中引入WebFlux路由,如何实现请求上下文传递?
解决方案:Spring MVC中为Reactive流注入请求上下文
在Spring MVC环境下混合使用Reactor(Mono/Flux)时,WebFlux的WebFilter不会生效,且不能通过@EnableWebFlux启用WebFlux栈(会与MVC冲突)。可以通过以下方式实现全局注入请求上下文到Reactor的Context中:
1. 替换WebFilter为Spring MVC过滤器
创建基于OncePerRequestFilter的MVC过滤器,通过Reactor钩子为所有返回的Reactive流注入请求信息:
import org.springframework.web.filter.OncePerRequestFilter; import reactor.core.publisher.Operators; import reactor.util.context.Context; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class ReactiveRequestContextMvcFilter extends OncePerRequestFilter { public static final String REQUEST_CONTEXT_KEY = "MVC_HTTP_REQUEST"; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 注册Reactor钩子,为所有后续的Mono/Flux注入请求上下文 var hook = Operators.onEachOperator("mvc-request-context", operator -> operator.transformDeferredContextual((mono, ctx) -> mono.subscriberContext(ctx.put(REQUEST_CONTEXT_KEY, request)))); try { filterChain.doFilter(request, response); } finally { // 清理钩子,避免内存泄漏 Operators.resetOnEachOperator("mvc-request-context", hook); } } }
2. 注册MVC过滤器
通过配置类将过滤器注册到Spring MVC容器:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.filter.OncePerRequestFilter; @Configuration public class MvcConfig { @Bean public OncePerRequestFilter reactiveRequestContextMvcFilter() { return new ReactiveRequestContextMvcFilter(); } }
3. 在控制器中获取上下文请求
使用Mono.deferContextual从Reactor Context中取出请求对象,进而获取请求头构建认证上下文:
@GetMapping("/{id}") public Mono<String> doSomething(@PathVariable("id") Long id) { return Mono.deferContextual(ctx -> { HttpServletRequest request = ctx.get(ReactiveRequestContextMvcFilter.REQUEST_CONTEXT_KEY); // 从请求头获取认证信息 String authHeader = request.getHeader("Authorization"); // 执行异步密集型任务 return Mono.fromCallable(() -> { // 业务逻辑处理 return "Processed task with auth: " + authHeader; }); }); }
关键说明
- 为什么不用WebFilter:
WebFilter是WebFlux栈的组件,Spring MVC的DispatcherServlet不会加载和执行它,因此必须使用MVC原生的OncePerRequestFilter。 - 为什么不能启用WebFlux:Spring MVC和WebFlux是两套独立的Web栈,同时启用会触发容器冲突报错,渐进式迁移时应保持MVC环境不变。
- Reactor Context的优势:相较于ThreadLocal,Reactor Context与订阅者绑定,在异步线程切换时不会丢失上下文,符合Reactive编程范式。
内容的提问来源于stack exchange,提问作者mpartan
相关产品推荐
相关产品推荐

