自定义DozerConverter仅在SpringBoot测试类生效,服务类不调用问题
Spring Boot下Dozer自定义转换器在业务类失效的解决方案
问题核心成因
映射失效是两类机制叠加导致:
- Dozer内置全局映射缓存会在首次调用
map方法时,将当前加载到的类映射关系永久固化,不会随后续Bean的初始化自动更新 - XML配置中硬编码的自定义转换器声明,会触发Dozer自行通过反射创建Converter实例,不会复用Spring容器中已经完成依赖注入的Converter Bean
测试场景下因为类加载顺序差异,未命中错误缓存,因此表现正常;正常Web应用启动时,业务Service提前触发首次map调用,Dozer将无完整Converter的错误映射关系写入缓存,后续即使Converter初始化完成,缓存关系也不会更新,最终出现SubEntity字段为null的问题。
可落地修复步骤
- 调整DozerBeanMapper的Bean初始化逻辑,完全接管自定义转换器的注册流程
直接将原本写在mappings.xml里的<converter>自定义转换器声明全部移除,仅保留普通字段的映射配置,避免触发Dozer自行实例化Converter的逻辑。在配置类的@Bean方法中,从Spring容器获取所有已初始化完成、依赖注入完整的DozerConverter实例,手动注册到Mapper中,示例代码如下:@Bean public DozerBeanMapper dozerBeanMapper(ApplicationContext context) { DozerBeanMapper mapper = new DozerBeanMapper(); // 保留XML中的普通字段映射配置 mapper.setMappingFiles(List.of("mappings.xml")); // 收集容器中所有Spring管理的自定义DozerConverter Collection<DozerConverter> springManagedConverters = context.getBeansOfType(DozerConverter.class).values(); for (DozerConverter converter : springManagedConverters) { // 按照转换器的源/目标类型注册,跳过Dozer自身的实例化流程 mapper.addCustomConverter(converter, converter.getSourceClass(), converter.getDestinationClass()); } return mapper; } - 初始化Mapper前清空Dozer全局静态缓存,清除残留的错误映射关系
Dozer 5.x及以下版本存在全局静态映射缓存,会跨实例复用之前加载的类映射关系,需要在创建DozerBeanMapper实例前执行缓存清理:// 清空Dozer内部缓存的旧类映射关系 org.dozer.cache.CacheFactory.clearAllEntries(); - 强制调整Bean初始化时序,保证Mapper实例的创建晚于所有自定义Converter的初始化完成
在定义DozerBeanMapper的Bean方法上添加@DependsOn注解,避免业务Service提前注入未完成配置的Mapper实例,示例:@Bean @DependsOn("entityToDtoDozerConverter") public DozerBeanMapper dozerBeanMapper(ApplicationContext context) { // 上述初始化逻辑 }
避坑提示
禁止让Dozer自身的实例化逻辑创建自定义Converter对象,所有标注了@Component的Converter必须完全由Spring容器管理,否则Converter中注入的业务依赖会为null,就算触发了转换逻辑也无法正常完成字段映射。
内容的提问来源于stack exchange,提问作者davnig
相关产品推荐
相关产品推荐

