Spring Boot中WebClient序列化配置Bean作为REST请求体报错解决
错误原因
你遇到的序列化错误,本质是因为给ConfigDetails加了@Configuration注解,Spring会为这个类生成CGLIB代理对象,代理对象中包含$$beanFactory这类Spring内部框架属性。Jackson序列化时会递归处理这些属性,但StandardBeanExpressionResolver这类Spring内部类没有对应的序列化器,因此抛出异常。
解决方案
方案1:修正配置Bean的注解(推荐)
@Configuration是用来定义配置类(比如注册Bean的类)的,而@ConfigurationProperties是用来绑定配置属性的,二者不应该混用。正确的做法是移除@Configuration,改用@Component让Spring扫描为Bean,或者通过@EnableConfigurationProperties来注册:
修改ConfigDetails类:
@ConfigurationProperties(prefix = "myprefix") @Component // 让Spring扫描并实例化 @Getter @Setter public class ConfigDetails { private String c1; private String c2; private String c3; }
然后在Spring Boot启动类添加@ConfigurationPropertiesScan,确保配置属性类被扫描到:
@SpringBootApplication @ConfigurationPropertiesScan public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } }
或者,如果你不想用@Component,可以在启动类用@EnableConfigurationProperties注册:
@SpringBootApplication @EnableConfigurationProperties(ConfigDetails.class) public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } }
此时ConfigDetails类可以去掉@Component,保留@ConfigurationProperties(prefix = "myprefix")即可。
这种方式从根源上避免了生成代理对象,是最规范的解决方法。
方案2:让Jackson忽略代理类的内部属性
如果因为某些原因必须保留@Configuration注解,可以在ConfigDetails类上添加@JsonIgnoreProperties,指定忽略Spring代理生成的特殊属性:
@ConfigurationProperties(prefix = "myprefix") @Configuration("configname") @Getter @Setter @JsonIgnoreProperties(value = {"$$beanFactory", "$$classLoader", "$$springConfigured"}) public class ConfigDetails { private String c1; private String c2; private String c3; }
或者更宽松地忽略所有未知属性(不推荐,可能会隐藏其他问题):
@JsonIgnoreProperties(ignoreUnknown = true)
方案3:使用DTO中转序列化
创建一个纯数据传输对象(DTO),将配置Bean的属性复制到DTO后再序列化,避免直接序列化Spring代理对象:
- 定义DTO类:
@Getter @Setter public class ConfigDetailsDto { private String c1; private String c2; private String c3; }
- 在调用WebClient时复制属性:
// 手动复制属性 ConfigDetailsDto dto = new ConfigDetailsDto(); dto.setC1(configDetails.getC1()); dto.setC2(configDetails.getC2()); dto.setC3(configDetails.getC3()); // 或者用Spring的BeanUtils简化复制 // BeanUtils.copyProperties(configDetails, dto); webClient.post().body(Mono.just(dto), ConfigDetailsDto.class)...
这种方式适合需要将配置Bean和请求体解耦的场景,避免后续配置Bean修改影响请求结构。
内容的提问来源于stack exchange,提问作者ashish.g

