Consider this simple example.
Class A {
B b;
A() {
this.b = new B(this);
}
}
In this example instance A knows about instance B, and instance B knows about instance A.
My question is: how to instantiate instance A with Guice, i.e. how to make Guice take care of this complex circle dependencies?
To resolve circular dependencies: Then there are three strategies you can use: Look for small pieces of code that can be moved from one project to the other. Look for code that both libraries depend on and move that code into a new shared library. Combine projectA and projectB into one library.
But circular dependencies in software are solvable because the dependencies are always self-imposed by the developers. To break the circle, all you have to do is break one of the links. One option might simply be to come up with another way to produce one of the dependencies, in order to bootstrap the process.
To remove the cycle using DI, we remove one direction of the two dependencies and harden the other one. To do that we should use an abstraction: in the order module, we add the DiscountCalculator interface. Thus, the Order class depends on this new type and the order module no longer depends on the customer module.
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.
Your example is not an issue at all, since you're constructing B directly. But if you want to both A and B to be created by Guice, one or both should be an interface. You can do:
public interface A { /* skipping methods */ }
public interface B { /* skipping methods */ }
public class AImpl implements A {
private final B b;
@Inject
public AImpl(B b) {
this.b = b;
}
// ...
}
public class BImpl implements B {
private final A a;
@Inject
public BImpl(A a) {
this.a = a;
}
// ...
}
Even if AImpl
and BImpl
are scoped as singletons, Guice can handle this injection (by way of a proxy). This works in a simple case like this at any rate... I imagine there could be more complex circular dependencies that it couldn't handle. Anyway, eliminating circular dependencies would be preferable, of course.
The answer is that you should not use a dependency injection framework while you have circular dependences in your code.
So, you have to refactor you code beforehand. As far as I know, there are two solutions for tightly coupled classes: either merge two classes into one or introduce new class and move common logic into it (for detail look here)
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