如何让Jackson反序列化生成的对象中@Autowired属性正确初始化?
问题原因
你遇到的问题本质是Jackson反序列化生成的BaseEventInfo对象并非Spring容器管理的Bean——Spring仅会对自身创建的实例执行依赖注入,因此@Autowired标记的someObject自然为null。
解决方案
以下几种方式可以在不传入依赖的前提下解决问题:
方案1:让Jackson通过Spring容器创建实例
配置ObjectMapper,使其借助Spring的Bean工厂完成对象实例化,这样反序列化后的对象会自动触发Spring的依赖注入。
在Spring Boot项目中,可自定义ObjectMapper配置:
@Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper(ApplicationContext context) { ObjectMapper objectMapper = new ObjectMapper(); // 注册Spring模块,让Jackson复用Spring的Bean创建逻辑 objectMapper.registerModule(new SpringModule()); // 或者通过自定义实例化器,手动触发Spring注入 objectMapper.setInstantiator(new StdInstantiatorProvider() { @Override public ObjectInstantiator findInstantiator(ValueType type, DeserializationConfig config, BeanDescription beanDesc) { ObjectInstantiator baseInstantiator = super.findInstantiator(type, config, beanDesc); return () -> { Object instance = baseInstantiator.newInstance(); // 让Spring为实例注入依赖 SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(instance); return instance; }; } }); return objectMapper; } }
使用这个配置后的ObjectMapper反序列化,BaseEventInfo中的someObject就会被正确注入。
方案2:拆分职责,将业务逻辑移至Spring服务类
把BaseEventInfo改为纯数据载体(DTO),移除@Component和@Autowired,将parseEvent的业务逻辑抽离到Spring管理的服务类中,更符合单一职责原则:
// 纯DTO,仅负责数据存储 public class BaseEventInfo { String mappedField; public String getMappedField() { return mappedField; } public void setMappedField(String mappedField) { this.mappedField = mappedField; } } // Spring管理的业务服务类 @Service public class EventProcessor { @Autowired SomeObject someObject; public void parseEvent(BaseEventInfo eventInfo) { someObject.doSomething(); // 此处处理eventInfo的业务逻辑 } }
调用方式改为:
BaseEventInfo eventInfo = objectMapper.readValue(eventJson, BaseEventInfo.class); eventProcessor.parseEvent(eventInfo);
方案3:手动从Spring上下文获取Bean(应急方案,不推荐)
如果必须在BaseEventInfo中保留parseEvent方法,可通过实现ApplicationContextAware手动获取依赖:
@Component public class BaseEventInfo implements ApplicationContextAware { private static ApplicationContext springContext; private SomeObject someObject; String mappedField; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { springContext = applicationContext; } public void parseEvent(){ if (someObject == null) { // 手动从上下文获取Bean someObject = springContext.getBean(SomeObject.class); } someObject.doSomething(); } // getter和setter不变 }
注意:这种方式会让BaseEventInfo与Spring上下文强耦合,静态上下文也会增加测试难度,仅建议临时应急使用。
内容的提问来源于stack exchange,提问作者coloradoman
相关产品推荐
相关产品推荐

