SpringBoot与MapStruct自动装配循环依赖问题求助
解决SpringBoot中MapStruct Mapper双向循环依赖问题
针对你遇到的MapStruct Mapper间双向依赖导致Spring启动报错的问题,以下是几种可行且无需放弃Spring自动装配特性的解决方案:
方案1:在Mapper接口中手动声明带@Lazy的依赖字段
MapStruct会根据接口定义的字段生成对应注入代码,只要在接口里给依赖的Mapper字段加上@Lazy和@Autowired注解,生成的实现类就会保留这些注解,通过延迟注入避免循环依赖。
示例代码:
// AssociatedAccountMapper.java @Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.FIELD) public interface AssociatedAccountMapper { // 结合CycleAvoidingMappingContext处理实体对象循环引用 @Mapping(target = "contactLocationRelations", ignore = false) AssociatedAccountDto toDto(AssociatedAccount entity, @Context CycleAvoidingMappingContext context); // 手动声明依赖的Mapper,添加@Lazy和@Autowired @Lazy @Autowired ContactLocationRelationMapper contactLocationRelationMapper; }
对应的ContactLocationRelationMapper同理:
// ContactLocationRelationMapper.java @Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.FIELD) public interface ContactLocationRelationMapper { ContactLocationRelationDto toDto(ContactLocationRelation entity, @Context CycleAvoidingMappingContext context); @Lazy @Autowired AssociatedAccountMapper associatedAccountMapper; }
方案2:构造器注入结合@Lazy参数
如果倾向于Spring推荐的构造器注入方式,可让MapStruct生成构造器注入代码,并在构造器参数上添加@Lazy注解,Spring支持通过带@Lazy的构造器参数处理循环依赖。
示例代码:
// AssociatedAccountMapper.java @Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR) public interface AssociatedAccountMapper { AssociatedAccountDto toDto(AssociatedAccount entity, @Context CycleAvoidingMappingContext context); // 构造器注入,参数添加@Lazy AssociatedAccountMapper(@Lazy ContactLocationRelationMapper contactLocationRelationMapper); }
ContactLocationRelationMapper做同样配置:
// ContactLocationRelationMapper.java @Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR) public interface ContactLocationRelationMapper { ContactLocationRelationDto toDto(ContactLocationRelation entity, @Context CycleAvoidingMappingContext context); ContactLocationRelationMapper(@Lazy AssociatedAccountMapper associatedAccountMapper); }
方案3:使用@MapperConfig统一配置注入策略
如果有多个Mapper需要处理,可通过@MapperConfig定义全局配置,避免重复代码:
// MapperConfig.java @MapperConfig(componentModel = "spring", injectionStrategy = InjectionStrategy.FIELD) public interface MapperConfig { }
然后在各个Mapper接口中引用该配置:
@Mapper(config = MapperConfig.class) public interface AssociatedAccountMapper { // 映射方法... @Lazy @Autowired ContactLocationRelationMapper contactLocationRelationMapper; }
注意事项
CycleAvoidingMappingContext负责处理实体对象间的循环引用(如A对象包含B集合、B对象包含A引用),而Mapper Bean间的循环依赖需要靠Spring的@Lazy解决,两者功能互补,需同时正确配置。- 所有注解必须加在Mapper接口上,不要手动修改MapStruct生成的Impl类,否则重新生成代码时配置会丢失。
内容的提问来源于stack exchange,提问作者Tom M
相关产品推荐
相关产品推荐

