如何配置Spring Boot Admin中Reactor库使用的ObjectMapper?
问题背景
在Kubernetes集群部署Spring Boot Admin服务后,已成功发现被监控服务,Insights、Logging页面功能正常,但JVM Thread Dump功能失效。
错误根源:被监控服务配置了objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);,当Spring Boot Admin请求/actuator/threaddump端点时,触发反序列化错误:无法将Object类型值反序列化为java.util.ArrayList<java.lang.Object>。
常规的自定义ObjectMapper Bean、Jackson2ObjectMapperBuilder配置无效,因为Spring Boot Admin的de.codecentric.boot.admin.server.web.servlet.InstancesProxyController基于Reactor栈(Flux、Mono)处理请求,其使用的ObjectMapper独立于应用全局配置。
解决方案
通过自定义Spring Boot Admin实例请求WebClient的Codec配置,为其添加匹配的Jackson反序列化特性:
- 实现
InstanceWebClientCustomizer接口,配置Jackson2JsonDecoder的反序列化规则 - 将自定义类注册为Spring Bean,让Spring Boot Admin自动加载该配置
代码实现
import org.springframework.boot.admin.server.web.client.InstanceWebClientCustomizer; import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.client.ExchangeStrategies; import org.springframework.web.reactive.function.client.WebClient; import com.fasterxml.jackson.databind.DeserializationFeature; @Component public class ThreadDumpWebClientCustomizer implements InstanceWebClientCustomizer { @Override public void customize(WebClient.Builder webClientBuilder) { ExchangeStrategies exchangeStrategies = ExchangeStrategies.builder() .codecs(configurer -> { Jackson2JsonDecoder decoder = new Jackson2JsonDecoder(); // 添加与被监控服务一致的反序列化特性 decoder.getObjectMapper().configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); configurer.defaultCodecs().jackson2JsonDecoder(decoder); }) .build(); webClientBuilder.exchangeStrategies(exchangeStrategies); } }
原理说明
InstanceWebClientCustomizer是Spring Boot Admin提供的扩展接口,用于自定义请求被监控实例端点的WebClient配置。通过修改WebClient的ExchangeStrategies,替换默认的Jackson2JsonDecoder并添加匹配的反序列化特性,即可让Spring Boot Admin正确解析/actuator/threaddump的返回数据,恢复Thread Dump功能。
版本兼容性
该方案适配Spring Boot 2.7.x + Spring Boot Admin 2.7.x版本,与你当前使用的依赖版本(Spring Boot 2.7.17、Spring Boot Admin 2.7.16)完全兼容。
内容的提问来源于stack exchange,提问作者Dmitriy Ten

