环境
- CacheCloud 3.4(在
main 分支同样可复现)
- Spring Boot 2.2.9.RELEASE / Spring Framework 5.2.x / Java 8
现象
Web 应用启动即失败,抛出:
org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'redisCenter':
Requested bean is currently in creation: Is there an unresolvable circular reference?
根因分析
MachineCenterImpl 和 AppScrollRestartServiceImpl 都通过 @Autowired 注入了 RedisCenter 的实现 RedisCenterImpl。
关键点:RedisCenterImpl 上存在 @Async 注解的方法(如 findInstancePatternKeys,返回 java.util.concurrent.Future,见 RedisCenterImpl.java:912)。@Async 要求 Spring 在 bean 完全初始化之后才为其生成异步代理(AsyncAnnotationBeanPostProcessor 处理)。
这导致该循环引用无法用 Spring 的“早期引用(early reference)”机制消解:
- 循环中的其他 bean 拿到的是
redisCenter 的半成品(原始对象),而容器最终放入的是异步代理;
- 代理必须在 bean 完全创建后才能生成,因此该循环在结构上“无法解析(unresolvable)”。
修复方案
在两个注入点加 @Lazy(注入懒加载代理占位符以打破循环,已验证有效):
cachecloud-web/src/main/java/com/sohu/cache/machine/impl/MachineCenterImpl.java
+import org.springframework.context.annotation.Lazy;
...
@Autowired
+ @Lazy
private RedisCenter redisCenter;
cachecloud-web/src/main/java/com/sohu/cache/web/service/impl/AppScrollRestartServiceImpl.java
+import org.springframework.context.annotation.Lazy;
...
@Autowired
+ @Lazy
private RedisCenter redisCenter;
main 分支对应行:MachineCenterImpl.java:79、AppScrollRestartServiceImpl.java:72。
复现步骤
- 按官方文档编译部署(profile=open,MySQL 已就绪)
- 启动 web 应用
- 启动日志即报上述异常
建议
除上述 @Lazy 最小修复外,也可考虑重构 MachineCenterImpl / AppScrollRestartServiceImpl 与 RedisCenter 之间的依赖,从根本上消除循环。
环境
main分支同样可复现)现象
Web 应用启动即失败,抛出:
根因分析
MachineCenterImpl和AppScrollRestartServiceImpl都通过@Autowired注入了RedisCenter的实现RedisCenterImpl。关键点:
RedisCenterImpl上存在@Async注解的方法(如findInstancePatternKeys,返回java.util.concurrent.Future,见RedisCenterImpl.java:912)。@Async要求 Spring 在 bean 完全初始化之后才为其生成异步代理(AsyncAnnotationBeanPostProcessor处理)。这导致该循环引用无法用 Spring 的“早期引用(early reference)”机制消解:
redisCenter的半成品(原始对象),而容器最终放入的是异步代理;修复方案
在两个注入点加
@Lazy(注入懒加载代理占位符以打破循环,已验证有效):cachecloud-web/src/main/java/com/sohu/cache/machine/impl/MachineCenterImpl.javacachecloud-web/src/main/java/com/sohu/cache/web/service/impl/AppScrollRestartServiceImpl.javamain分支对应行:MachineCenterImpl.java:79、AppScrollRestartServiceImpl.java:72。复现步骤
建议
除上述
@Lazy最小修复外,也可考虑重构MachineCenterImpl/AppScrollRestartServiceImpl与RedisCenter之间的依赖,从根本上消除循环。