Spring 5.3.9带状态Converter无法识别,@Lazy为何能解决?
场景还原
1. 初始正常的无状态Converter
基于Spring 5.3.9,以下无状态Converter可被Spring正常识别并运行:
class Conv implements Converter<A, B> { public B convert(A a) { // 转换逻辑实现 } }
2. 添加依赖后出现识别问题
当给Converter引入其他Bean依赖,改为有状态版本后:
class Conv implements Converter<A, B> { private final X x; public Conv(X x) { this.x = x; } public B convert(A a) { // 依赖X的转换逻辑 } }
运行时会抛出如下错误:
No converter found capable of converting from type [A] to type [B]
需要注意:Conv本身能被Spring成功创建,Bean生命周期正常,依赖注入无异常(调试可进入构造方法),尝试构造注入、@Autowired注入均无法解决识别问题。
3. @Lazy注解修复问题
给构造方法参数添加@Lazy注解后,Converter可被正常识别使用:
class Conv implements Converter<A, B> { private final X x; public Conv(@Lazy X x) { this.x = x; } public B convert(A a) { // 转换逻辑实现 } }
注:无法复现最小示例,推测问题与真实项目中的Bean依赖关系有关。
原因分析
Spring中Converter的注册时机很早,属于BeanFactory初始化阶段的早期任务——Spring会提前收集所有实现Converter接口的Bean,用于构建全局ConversionService。
当Conv依赖X时,如果X的初始化流程间接依赖了未完成注册的ConversionService(比如X中用到需要类型转换的逻辑,触发了ConversionService的调用),就会形成循环依赖链:
- 要注册Conv到ConversionService,需先实例化Conv;要实例化Conv,需先实例化X;
- 但实例化X时又需要用到ConversionService,此时ConversionService还未完成Conv的注册,Spring为避免死锁,会跳过Conv的注册,最终出现找不到Converter的报错。
添加@Lazy注解后,Spring不会直接实例化真实的X Bean,而是给Conv注入一个X的代理对象:
- Conv可快速完成实例化,顺利被注册到ConversionService中;
- 真实的X Bean会在第一次被实际调用时才初始化,此时ConversionService已完成所有Converter的注册,循环依赖链条被打破,Conv自然能被正常识别。
此外,Spring 5.3.x对这类早期组件(如Converter)的依赖处理逻辑较严格,@Lazy通过延迟依赖Bean的初始化,刚好避开了早期注册阶段的循环依赖冲突,从而解决问题。
内容的提问来源于stack exchange,提问作者aviad cohen

