Spring 随机出现引导交叉引用问题
Spring boot cross-reference issue randomly occurs
我在构建 Spring 启动项目时遇到循环依赖(交叉引用)问题,依赖趋势如下:
- 处理器 class 通过构造函数注入自动装配条件class;
- Criteria class 通过构造函数注入自动装配 CacheManager;
- CahceManager class 通过 setter 注入自动装配规则集 class;
- RuleSet class 通过构造函数注入再次自动装配处理器。
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 class 中移除 Processor 的依赖关系,但我想知道是否存在是一种保留当前引用但仍然消除此处介绍的交叉引用问题的方法吗?我查看了这个论坛,有人建议 @Lazy 注释可能有帮助。我尝试将它应用于处理器 class 或规则集 class(在 class 级别或方法级别),问题并没有消失。
另一个观察是,上面引用的错误并没有一直出现——有时程序运行得很好,是随机出现的错误让我很烦恼。为什么会这样?
您可以在一处用字段注入替换构造函数注入。它将打破循环对象实例化的循环。
很难说为什么会时不时出现这个问题。也许,有一些 @Configuration
类 根据配置值构建同一接口的不同实现。你应该提供更多细节来处理这个问题。
解决它的一种方法是用这样的 Provider
替换一个实例:
public Processor(Provider<Criteria> criteria) {
this.criteria = criteria;
}
那么在使用的时候需要先get()
Criteria c = this.criteria.get();
这意味着 Processor
可以在 Criteria
之前构建,因为注入的 Provider
将在准备就绪后获得 Criteria
bean。
这意味着您不能在构造函数中调用 get()
,否则会出现运行时错误,因为这仍然意味着循环构造依赖。
@Lazy
只是意味着 Spring 应该等待初始化一个 bean,直到它被实际请求,而不是在启动时急切地创建它(这是标准行为)。这对循环依赖和注入其他 beans 构造函数的 beans 的影响为零。它对于初始化非常慢并且必须几乎总是从 Provider
使用以实际延迟初始化的 bean 很有用。
我在构建 Spring 启动项目时遇到循环依赖(交叉引用)问题,依赖趋势如下:
- 处理器 class 通过构造函数注入自动装配条件class;
- Criteria class 通过构造函数注入自动装配 CacheManager;
- CahceManager class 通过 setter 注入自动装配规则集 class;
- RuleSet class 通过构造函数注入再次自动装配处理器。
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 class 中移除 Processor 的依赖关系,但我想知道是否存在是一种保留当前引用但仍然消除此处介绍的交叉引用问题的方法吗?我查看了这个论坛,有人建议 @Lazy 注释可能有帮助。我尝试将它应用于处理器 class 或规则集 class(在 class 级别或方法级别),问题并没有消失。
另一个观察是,上面引用的错误并没有一直出现——有时程序运行得很好,是随机出现的错误让我很烦恼。为什么会这样?
您可以在一处用字段注入替换构造函数注入。它将打破循环对象实例化的循环。
很难说为什么会时不时出现这个问题。也许,有一些 @Configuration
类 根据配置值构建同一接口的不同实现。你应该提供更多细节来处理这个问题。
解决它的一种方法是用这样的 Provider
替换一个实例:
public Processor(Provider<Criteria> criteria) {
this.criteria = criteria;
}
那么在使用的时候需要先get()
Criteria c = this.criteria.get();
这意味着 Processor
可以在 Criteria
之前构建,因为注入的 Provider
将在准备就绪后获得 Criteria
bean。
这意味着您不能在构造函数中调用 get()
,否则会出现运行时错误,因为这仍然意味着循环构造依赖。
@Lazy
只是意味着 Spring 应该等待初始化一个 bean,直到它被实际请求,而不是在启动时急切地创建它(这是标准行为)。这对循环依赖和注入其他 beans 构造函数的 beans 的影响为零。它对于初始化非常慢并且必须几乎总是从 Provider
使用以实际延迟初始化的 bean 很有用。