能否在Undertow中同时运行Spring WebFlux与MVC(CXF、Shiro等)服务?
在Undertow中同时运行Spring MVC和Reactive WebFlux服务的方案
当然可以!你遇到的问题是因为Spring Boot默认会根据依赖自动选择Servlet栈(MVC)或Reactive栈(WebFlux),一旦选定就会禁用另一套核心组件,但通过手动配置上下文和Undertow容器适配,完全可以让两类服务共存。下面是具体的实现步骤和注意事项:
1. 确保依赖同时包含MVC和WebFlux
首先,在你的构建文件(Maven/Gradle)中同时引入Spring Web(MVC)和Spring WebFlux的starter,不要让Spring Boot自动排除任何一方:
Maven示例:
<dependencies> <!-- Spring MVC 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring WebFlux 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <!-- 你的其他依赖:Apache CXF、Shiro等 --> </dependencies>
默认情况下,Spring Boot会优先启用Servlet栈(MVC),但WebFlux的端点不会自动注册,需要手动配置路由映射。
2. 配置Undertow同时处理MVC和WebFlux请求
我们需要手动把WebFlux的请求处理器绑定到Undertow的非阻塞处理链,让特定路径的请求由WebFlux处理,其余请求交给MVC/CXF处理:
import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.server.reactive.UndertowServerHttpRequest; import org.springframework.http.server.reactive.UndertowServerHttpResponse; import org.springframework.web.reactive.DispatcherHandler; import org.springframework.web.server.ServerHttpRequest; import org.springframework.web.server.ServerHttpResponse; import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory; import io.undertow.servlet.api.DeploymentInfo; import static io.undertow.Handlers.path; @Configuration public class DualStackWebConfig { @Bean public UndertowServletWebServerFactory undertowServerFactory(ApplicationContext context) { UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory(); // 获取WebFlux的核心处理器 DispatcherHandler webFluxDispatcher = context.getBean(DispatcherHandler.class); factory.addDeploymentInfoCustomizers((DeploymentInfo deploymentInfo) -> { // 创建路径处理器:把/reactive/**的请求转发给WebFlux HttpHandler webFluxHandler = exchange -> { ServerHttpRequest request = new UndertowServerHttpRequest(exchange); ServerHttpResponse response = new UndertowServerHttpResponse(exchange); webFluxDispatcher.handle(request, response).block(); }; // 把WebFlux处理器添加到Undertow的处理链 deploymentInfo.addOuterHandlerChainWrapper(rootHandler -> path() .addPrefixPath("/reactive", webFluxHandler) .addPrefixPath("/", rootHandler) ); }); return factory; } }
这样,所有/reactive/**前缀的请求会被WebFlux处理,其他请求(包括MVC控制器、CXF REST服务)依然由Servlet栈处理。
3. 适配Shiro安全机制到双栈
因为Shiro默认是基于Servlet的过滤器,需要同时配置适用于MVC的Servlet过滤器和适用于WebFlux的路由过滤器:
保持原有的Shiro MVC配置(用于Servlet栈)
@Configuration public class ShiroMvcConfig { @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean(); factoryBean.setSecurityManager(securityManager); // 你的原有过滤器链配置,比如: Map<String, String> filterChain = new HashMap<>(); filterChain.put("/mvc/secured/**", "authc"); filterChain.put("/cxf/rest/**", "authc"); factoryBean.setFilterChainDefinitionMap(filterChain); return factoryBean; } // 其他Shiro相关Bean:SecurityManager、Realm等... }
添加Shiro WebFlux配置(用于响应式栈)
@Configuration public class ShiroWebFluxConfig { @Bean public ShiroWebFilter shiroWebFilter(SecurityManager securityManager) { ShiroWebFilter webFilter = new ShiroWebFilter(); webFilter.setSecurityManager(securityManager); // 配置响应式路径的安全规则 Map<String, String> filterChain = new HashMap<>(); filterChain.put("/reactive/secured/**", "authc"); webFilter.setFilterChainDefinitionMap(filterChain); return webFilter; } // 将Shiro过滤器绑定到WebFlux路由 @Bean public RouterFunction<ServerResponse> securedReactiveRoutes(ShiroWebFilter shiroFilter) { return RouterFunctions.route() .GET("/reactive/secured/hello", req -> ServerResponse.ok().bodyValue("Secured Reactive Response")) .filter(shiroFilter) .build(); } }
4. 关键注意事项
- 路径隔离:务必确保MVC、CXF和WebFlux的路径没有重叠,否则会导致请求处理混乱(比如
/api/**不要同时被MVC和WebFlux使用)。 - 线程模型差异:MVC使用阻塞IO线程池,WebFlux使用Undertow的非阻塞IO线程池,需要根据服务负载调整两类线程池的大小,避免资源竞争。
- Spring版本:建议使用Spring 5.3及以上版本,早期版本对双栈共存的支持不够完善。
- CXF兼容性:CXF是基于Servlet的REST框架,它的端点会自动融入Servlet栈,无需额外调整,只要路径不冲突即可。
通过以上配置,你就能在Undertow容器中同时运行MVC风格服务、Apache CXF REST服务和Spring Reactive响应式服务了。
内容的提问来源于stack exchange,提问作者KJQ
相关产品推荐
相关产品推荐

