I am using Guice for Dependency Injection and want to create an object graph that looks like this:
d1 d2 / \ / \ b1 c1 b2 c2 \ / \ / a1 a2
- a1 and a2 denote instance of class A etc.
- class A depends on classes B and C
- classes B and C each depend on class D
- However, the instance of D used in B and C should be the same
So I want to create two instances of the A class, each with this structure. A use case could be D being some kind of data object (say, a DB connection) that is used by the two clients B and C, that both are used in a servlet A.
Minimal Java class definition:
public class A {
@Inject A(B b, C c) {}
}
public class B {
@Inject B(D d) {}
}
public class C {
@Inject C(D d) {}
}
public class D {}
Now I can create two instances of A:
Injector injector = Guice.createInjector(new DiamondModule());
A a1 = injector.getInstance(A.class);
A a2 = injector.getInstance(A.class);
However, if I do this, I will get four different instances of D, which is not what I want. Notice that declaring D a singleton will not help, as then I will get only a single instance of D.
I have seen the following question, but the answer to that one doesn't work here, or at least I do not know how: Guice inject single instance into multiple objects without using @Singleton
Does anyone have an idea how to solve this? Or is this design somehow wrong? Or is this already an instance where I have to declare my own scope?
Solution
Meanwhile I noticed that this question is a duplicate of Dependency injection: Scoping by region (Guice, Spring, Whatever), and based on the anwers to that question I came up with a solution.
The basic idea is to create a new injector for every instance of the diamond, like this:
public class MainModule extends AbstractModule {
@Override
protected void configure() {
}
@Provides
A createA() {
return Guice.createInjector().getInstance(A.class);
}
}
Now make D an singleton, which is scoped to the particular injector.
// class D is a singleton
@Singleton
public class D {}