Spring WebClient调用Rest服务遇Jaxb2XmlDecoder异常,如何配置Decoder?
解决WebClient调用时Jaxb2XmlDecoder的UnsupportedOperationException问题
嘿,我来帮你搞定这个困扰!你遇到的UnsupportedOperationException来自Jaxb2XmlDecoder的decodeToMono方法,本质原因是在Spring 5.0.3这个版本里,Jaxb2XmlDecoder是基于同步XML解析实现的,并没有完全适配WebClient所需的响应式解码逻辑。下面是针对非Spring Boot的Spring MVC应用的具体配置方案:
方案一:改用Jackson XML解码器(推荐)
Jackson的XML解码器是完全响应式实现的,完美适配WebClient的异步调用场景,还能兼容JAXB注解(如果你的DTO用了这些注解的话)。
1. 添加必要依赖
如果用Maven,在pom.xml里加入以下依赖(版本选和Spring 5.0.3兼容的2.9.x系列,适配性最好):
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.module</groupId> <artifactId>jackson-module-jaxb-annotations</artifactId> <version>2.9.8</version> </dependency>
2. 配置WebClient时替换XML解码器
手动创建WebClient的时候,自定义ExchangeStrategies来替换默认的XML解码器:
import org.springframework.http.codec.xml.Jackson2XmlDecoder; import org.springframework.web.reactive.function.client.ExchangeStrategies; import org.springframework.web.reactive.function.client.WebClient; // 构建自定义的ExchangeStrategies,替换XML解码逻辑 ExchangeStrategies reactiveStrategies = ExchangeStrategies.builder() .codecs(configurer -> { // 注册Jackson XML解码器 configurer.defaultCodecs().jackson2XmlDecoder(new Jackson2XmlDecoder()); // 如果你的WebClient需要发送XML请求,也可以配置对应的编码器 // configurer.defaultCodecs().jackson2XmlEncoder(new Jackson2XmlEncoder()); }) .build(); // 使用自定义策略创建WebClient WebClient yourWebClient = WebClient.builder() .exchangeStrategies(reactiveStrategies) .baseUrl("你的REST服务基础地址") .build();
方案二:坚持使用JAXB解码器(仅当项目依赖JAXB特定功能时)
如果你的项目必须依赖JAXB的功能,有两个可选方向:
- 升级Spring版本到5.1+:Spring 5.1及以后的版本完善了
Jaxb2XmlDecoder的响应式方法实现,直接就能用,不需要额外配置。 - 自定义适配解码器:如果不想升级Spring版本,可以自己封装一个基于JAXB的响应式解码器,把同步的JAXB解码逻辑包装到
Mono中。示例代码大概是这样:
import org.springframework.core.ResolvableType; import org.springframework.http.MediaType; import org.springframework.http.codec.Decoder; import org.springframework.http.codec.xml.Jaxb2XmlDecoder; import reactor.core.publisher.Mono; import java.io.InputStream; import java.util.List; public class ReactiveJaxbDecoder implements Decoder<Object> { private final Jaxb2XmlDecoder delegate = new Jaxb2XmlDecoder(); @Override public boolean canDecode(ResolvableType elementType, MediaType mediaType) { return delegate.canDecode(elementType, mediaType); } @Override public List<MediaType> getDecodableMediaTypes() { return delegate.getDecodableMediaTypes(); } @Override public Mono<Object> decodeToMono(InputStream inputStream, ResolvableType elementType, MediaType mediaType, java.util.Map<String, Object> hints) { // 把同步解码逻辑包装到Mono中,用subscribeOn切换到IO线程池避免阻塞 return Mono.fromCallable(() -> delegate.decode(inputStream, elementType, mediaType, hints)) .subscribeOn(reactor.core.scheduler.Schedulers.boundedElastic()); } // 如果你需要支持Flux,也可以实现decodeToFlux方法 }
然后在WebClient的ExchangeStrategies里注册这个自定义解码器即可。
最后提醒
不管选哪个方案,都要确保REST服务返回的XML媒体类型(比如application/xml、text/xml)能被你配置的解码器正确识别,这样WebClient才能自动匹配到对应的解码逻辑。
内容的提问来源于stack exchange,提问作者user871611
相关产品推荐
相关产品推荐

