I know you’ve been there, like me:
- I Have a circular dependency in Spring and my application fails to launch. How to solve this?
The typical exception thrown by Spring is the following:
‘org.springframework.security.authenticationManager’: Requested bean is currently in creation: Is there an unresolvable circular reference?
And, It does not give much details. So, let’s see how we can break the circular dependency cycle and save some sanity!
Understand the Issue
Let’s take a very simple example to illustrate the issue. Here is part of our code handling the application permissions.
|
|
The SpringPermissionEvaluator
then requires all the PermissionByObject
implementations to be injected via collection autowiring.
|
|
Suppose now that we have the following implementation named WorkspaceByObject
:
|
|
We have a circular dependency here:
SystemPermissionEvaluator
requires allPermissionByObject
on construction,WorkspaceByObject
implementsPermissionByObject
and requiresSystemPermissionEvaluator
on construction.
We’re going to explore the ways we can solve this issue.
Field Autowiring
The first and most obvious solution is to prevent the WorkspaceByObject
from requiring the SystemPermissionEvaluator
upon construction by using Field injection.
|
|
SystemPermissionEvaluator injected via Field Injection
Setter Autowiring
Or Setter Injection:
|
|
SystemPermissionEvaluator injected via Setter Injection
Another solution would be to apply the same trick to the SystemPermissionEvaluator
. Why does it work? Because Spring can inject the dependencies after construction.
Using @Lazy
The @Lazy annotation allows Spring to inject a Java Proxy of your bean, instead of the bean itself. It can resolves the cycle by instantiating the beans when a method on it is called.
|
|
Because @Lazy
proxyfies your bean, calls to your service are done through reflection, thus being 2x slower than direct calls. Therefore, I would recommend using @Lazy
only when nothing else is possible.
Using @PostConstruct
PostConstruct can be used to annotate a method which is then called once the bean has been properly autowired. It can be effectively used to fix a circular dependency, although you should be aware it’s pretty ugly to do so.
We can do so by altering the permission interface:
|
|
As you can see, this will pretty much affect every single PermissionByObject
implementation even if it’s not using the SystemPermissionEvaluator
…
Then, we’ll do this in the SystemPermissionEvaluator
:
|
|
Needless to say, this solution is exposing the internals of a specific permission to everyone. It’s also affecting permissions which don’t need the SystemPermissionEvaluator
being injected.
So, what can be do to solve this issue properly?
Using @Configuration
Another solution is to register the PermissionByObject
instances into the SystemPermissionEvaluator
using an external Spring Configuration within the same package. The key is to keep the registering logic invisible to external callers.
|
|
By doing this, the cycle is broken down. Both permission evaluator and permissions can be instantiated independently.
Changing the Code
A circular dependency issue should be an alarm screaming: Hey, there is something wrong with your code architecture! Of course, it’s not always possible to fix the issue by yourself. It may happen due to a badly designed library you are depending on.
After figuring it out, in fact the WorkspaceByObject
has been rewritten (as well as other parts of the permission system) to completely avoid injecting the SystemPermissionEvaluator
at all!
Final Words
Always consider redesigning your code before deep diving into fancy solutions to fix spring circular dependencies issues. Use the methods described here as last resort when nothing else is possible.
Remember Spring isn’t difficult! There is a solution to every problem related to Spring, and chances are that you are not the single one experiencing those issues. Always look on Spring StackOverflow to see if someone else has had the same issue.