如何在Spring Data Rest应用中注册Converter并避免循环Bean依赖
这个循环依赖坑我之前踩过好几次,也帮不少开发者解决过——本质是RepositoryRestConfigurerAdapter的配置类初始化时,会被Spring Data REST的核心组件提前触发,而你又在配置类里直接注入了EnumTranslator,导致双方互相等待对方初始化完成,形成死循环。下面给你几个经过验证的解决办法,按推荐程度排序:
方案1:让EnumTranslator自动注册(最简洁)
如果你的EnumTranslator是自定义的Converter实现,可以让它实现ConverterRegistryAware接口。Spring会自动识别这个接口,并在初始化时把转换器注册到ConversionService里,完全不需要你在RepositoryRestConfigurerAdapter里手动注册,从根源上避免循环依赖。
示例代码:
@Component public class EnumTranslator implements Converter<String, YourTargetEnum>, ConverterRegistryAware { @Override public YourTargetEnum convert(String source) { // 这里写你的枚举转换逻辑 return YourTargetEnum.valueOf(source.toUpperCase()); } @Override public void setConverterRegistry(ConverterRegistry registry) { // 把自身注册到转换器注册表 registry.addConverter(this); } }
方案2:用@Lazy延迟加载打破循环
如果EnumTranslator是第三方组件或者没法修改源码,那就在配置类注入它的时候加上@Lazy注解,让Spring延迟初始化这个Bean,避免在配置类初始化阶段就触发它的创建,从而打破循环链。
示例代码:
@Configuration public class RestDataConfig extends RepositoryRestConfigurerAdapter { private final EnumTranslator enumTranslator; // 给构造器注入的依赖添加@Lazy public RestDataConfig(@Lazy EnumTranslator enumTranslator) { this.enumTranslator = enumTranslator; } @Override public void configureConversionService(ConfigurableConversionService conversionService) { conversionService.addConverter(enumTranslator); super.configureConversionService(conversionService); } }
方案3:通过BeanPostProcessor动态注册
如果上面两种方式都不适用,可以用Spring的BeanPostProcessor来动态拦截ConfigurableConversionService的初始化,在它创建完成后再注册转换器。这种方式完全绕过了RepositoryRestConfigurerAdapter的初始化流程,彻底避免循环。
示例代码:
@Component public class EnumTranslatorRegistrar implements BeanPostProcessor { private final EnumTranslator enumTranslator; // 同样如果有循环,给依赖加@Lazy public EnumTranslatorRegistrar(@Lazy EnumTranslator enumTranslator) { this.enumTranslator = enumTranslator; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { // 识别到ConversionService实例时注册转换器 if (bean instanceof ConfigurableConversionService) { ConfigurableConversionService conversionService = (ConfigurableConversionService) bean; conversionService.addConverter(enumTranslator); } return bean; } }
小提示
优先用方案1,代码最简洁也最符合Spring的设计理念;如果没法修改EnumTranslator,就用方案2,改动最小;方案3适合复杂场景下的自定义注册逻辑。
内容的提问来源于stack exchange,提问作者Patrik Mihalčin

