Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Guice with circular dependencies

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?

like image 416
Yury Litvinov Avatar asked Sep 26 '09 18:09

Yury Litvinov


People also ask

How do you resolve circular dependency in react?

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.

How do you solve circular dependency injection?

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.

How do you break cyclic dependency?

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.

How does Spring overcome circular dependency?

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.


2 Answers

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.

like image 136
ColinD Avatar answered Nov 07 '22 20:11

ColinD


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)

like image 31
Yury Litvinov Avatar answered Nov 07 '22 22:11

Yury Litvinov