I've read that circular dependencies
are caused by setter
injection. So I tried to check it by my own. And it appears that I can reproduce circular dependency
only with constructor
injection (see code below).
So the questions:
circular dependency
with setter
injection?How to resolve circular dependencies
at code below?
public class AConstr {
private final BConstr b;
public AConstr(BConstr bConstr) {
System.out.println("AConstructor:: constructor");
this.b = bConstr;
}
}
public class BConstr {
private final AConstr a;
public BConstr(AConstr aConstr) {
System.out.println("BConstructor:: constructor");
this.a = aConstr;
}
}
<bean id="aConstr" class="pack.bean.AConstr">
<constructor-arg ref="bConstr"/>
</bean>
<bean id="bConstr" class="pack.bean.BConstr">
<constructor-arg ref="aConstr"/>
</bean>
Circular dependency in Spring happens when two or more beans require instance of each other through constructor dependency injections. For example: There is a ClassA that requires an instance of ClassB through constructor injection and ClassB requires an instance of class A through constructor injection.
A simple way to break the cycle is by telling Spring to initialize one of the beans lazily. So, instead of fully initializing the bean, it will create a proxy to inject it into the other bean. The injected bean will only be fully created when it's first needed.
To reduce or eliminate circular dependencies, architects must implement loose component coupling and isolate failures. One approach is to use abstraction to break the dependency chain. To do this, you introduce an abstracted service interface that delivers underlying functionality without direct component coupling.
There are 2 ways of injecting dependencies with Spring @Autowired
: by field or by constructor.
If you have the following layers:
With the following bindings:
FooController BarController + + | | + + FooService<-------->BarService + + | | + + FooJpaRepository BarJpaRepository + + | | + + FooEntity BarEntity
Thus, it's normal that 2 Services can depend from each other (directly or not), and that's why you can break the circular dependency:
@Autowired
on fields instead of on constructor in one of your Service@Lazy
before a constructor parameter.here is what Spring suggests: https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-dependencies
On the other hand, a Service (or directly a JpaRepository) should be injected to RestControllers by constructor. In that case a circular dependency would be an architecture problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With