I got a circular dependencies (cross-reference) issue when building a Spring boot project, and the dependencies trend like below:
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 ...
└─────┘
While I can make an effort to remove the dependency of Processor from RuleSet class, I was wondering if there is a way of keeping the current references but still eliminating the cross-reference issue as presented here? I looked up this forum and someone suggested that the @Lazy annotation might help. I tried to apply it to either the Processor class or the RuleSet class (on either class level or method level), the issue didn't go away.
Another observation is that, the above quoted error didn't appear all the time - sometime the program proceeds just fine, it's that the error randomly occurs that bugged me. And why is that?
One way to solve it is to replace one instance with a Provider
like this:
public Processor(Provider<Criteria> criteria) {
this.criteria = criteria;
}
Then when using it you need to get()
it first.
Criteria c = this.criteria.get();
This means that Processor
can be constructed before Criteria
since the injected Provider
will get the Criteria
bean once it's ready.
This means that you cannot call get()
in the constructor or you'll get a runtime error since that would still mean a circular construction dependency.
@Lazy
just means that Spring should wait with initialising a bean until it is actually requested instead of eagerly creating it on startup (which is standard behaviour). This has zero impact on both circular dependencies and beans that are injected into other beans constructors. It is useful for beans that are very slow to initialize and must almost always be used from a Provider
to actually defer initialisation.