问题描述
我在构建 Spring Boot 项目时遇到了循环依赖(交叉引用)问题,并且依赖趋势如下:
- Processor 类通过构造函数注入自动装配 Criteria 类;
- Criteria 类通过构造函数注入自动装配 CacheManager;
- CahceManager 类通过 setter 注入自动装配了 RuleSet 类;
- RuleSet 类通过构造函数注入再次自动装配处理器。
The dependencies of some of the beans in the application context form a cycle:
app
┌─────┐
| XXXProcessor defined in file ...
↑ ↓
| XXXCriteria defined in file ...
↑ ↓
| XXXCacheManager
↑ ↓
| XXXRuleSet defined in file ...
└─────┘
虽然我可以努力从 RuleSet 类中删除 Processor 的依赖项,但我想知道是否有一种方法可以保留当前引用但仍然消除此处介绍的交叉引用问题?我查了一下这个论坛,有人建议 @Lazy 注释可能会有所帮助。我尝试将其应用于 Processor 类或 RuleSet 类(在类级别或方法级别),但问题并未消失。
另一个观察结果是,上面引用的错误并不是一直出现 - 有时程序运行得很好,是随机出现的错误让我烦恼。为什么会这样?
解决方法
您可以在一处用字段注入替换构造函数注入。它将打破循环对象实例化的循环。
很难说为什么会不时发生这个问题。也许,有一些 2021-04-26 08:59:592021-04-26T15:59:59Z [Debug] Shutdown Initiated. Current epoch in nanoseconds: 1619452799073953600
2021-04-26 08:59:592021-04-26T15:59:59Z [Info] Got shutdown signal: terminated
2021-04-26 08:59:592021-04-26T15:59:59Z [Debug] Skipped telemetry data as no segments found
2021-04-26 08:59:592021-04-26T15:59:59Z [Debug] telemetry: done!
2021-04-26 08:59:592021-04-26T15:59:59Z [Debug] Segment batch: done!
2021-04-26 08:59:592021-04-26T15:59:59Z [Debug] Segment batch: done!
2021-04-26 08:59:592021-04-26T15:59:59Z [Debug] Segment batch: done!
2021-04-26 08:59:592021-04-26T15:59:59Z [Debug] Segment batch: done!
2021-04-26 08:59:592021-04-26T15:59:59Z [Debug] Segment batch: done!
2021-04-26 08:59:592021-04-26T15:59:59Z [Debug] Segment batch: done!
2021-04-26 08:59:592021-04-26T15:59:59Z [Debug] Segment batch: done!
2021-04-26 08:59:592021-04-26T15:59:59Z [Debug] Segment batch: done!
2021-04-26 08:59:592021-04-26T15:59:59Z [Debug] processor: done!
2021-04-26 08:59:592021-04-26T15:59:59Z [Debug] Trace segment: received: 0,truncated: 0,processed: 0
2021-04-26 08:59:592021-04-26T15:59:59Z [Debug] Shutdown finished. Current epoch in nanoseconds: 1619452799074286437
2021-04-26 08:59:582021-04-26T15:59:58Z [Info] Starting proxy http server on 0.0.0.0:2000
2021-04-26 08:59:582021-04-26T15:59:58Z [Error] Get instance id metadata failed: RequestError: send request failed
2021-04-26 08:59:58caused by: Get http://169.254.169.254/latest/meta-data/instance-id: dial tcp 169.254.169.254:80: connect: invalid argument
2021-04-26 08:59:582021-04-26T15:59:58Z [Debug] Using Endpoint: https://xray.us-east-1.amazonaws.com
2021-04-26 08:59:582021-04-26T15:59:58Z [Debug] Telemetry initiated
2021-04-26 08:59:582021-04-26T15:59:58Z [Info] HTTP Proxy server using X-Ray Endpoint : https://xray.us-east-1.amazonaws.com
2021-04-26 08:59:582021-04-26T15:59:58Z [Debug] Using Endpoint: https://xray.us-east-1.amazonaws.com
2021-04-26 08:59:582021-04-26T15:59:58Z [Debug] Batch size: 50
2021-04-26 08:59:572021-04-26T15:59:57Z [Debug] Get hostname metadata failed: RequestError: send request failed
2021-04-26 08:59:57caused by: Get http://169.254.169.254/latest/meta-data/hostname: dial tcp 169.254.169.254:80: connect: invalid argument
2021-04-26 08:59:572021-04-26T15:59:57Z [Debug] Using proxy address:
2021-04-26 08:59:572021-04-26T15:59:57Z [Debug] Fetch region us-east-1 from environment variables
2021-04-26 08:59:572021-04-26T15:59:57Z [Info] Using region: us-east-1
2021-04-26 08:59:572021-04-26T15:59:57Z [Debug] ARN of the AWS resource running the daemon:
2021-04-26 08:59:572021-04-26T15:59:57Z [Info] Initializing AWS X-Ray daemon 3.2.0
2021-04-26 08:59:572021-04-26T15:59:57Z [Debug] Listening on UDP 0.0.0.0:2000
2021-04-26 08:59:572021-04-26T15:59:57Z [Info] Using buffer memory limit of 37 MB
2021-04-26 08:59:572021-04-26T15:59:57Z [Info] 592 segment buffers allocated
类根据配置值构建相同接口的不同实现。您应该提供更多详细信息来处理此问题。
解决此问题的一种方法是将一个实例替换为 Provider
,如下所示:
public Processor(Provider<Criteria> criteria) {
this.criteria = criteria;
}
然后在使用时需要先get()
。
Criteria c = this.criteria.get();
这意味着 Processor
可以在 Criteria
之前构造,因为注入的 Provider
一旦准备好将获得 Criteria
bean。
这意味着您不能在构造函数中调用 get()
否则您将收到运行时错误,因为这仍然意味着循环构造依赖。
@Lazy
只是意味着 Spring 应该等待初始化 bean 直到它被实际请求,而不是在启动时急切地创建它(这是标准行为)。这对循环依赖项和注入其他 bean 构造函数的 bean 的影响为零。对于初始化非常慢并且必须几乎总是从 Provider
使用以实际延迟初始化的 bean 很有用。