考虑这个简单的例子。
Class A {
B b;
A() {
this.b = new B(this);
}
}
在此示例中,实例A了解实例B,实例B知道实例A.
我的问题是:如何使用Guice实例化实例A,即如何让Guice处理这个复杂的循环依赖?
答案 0 :(得分:9)
你的例子根本不是问题,因为你是直接构建B的。但是如果你想要由Guice创建A和B,则一个或两个应该是一个接口。你可以这样做:
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;
}
// ...
}
即使AImpl
和BImpl
的范围是单身,Guice也可以处理此注入(通过代理)。无论如何,这在一个简单的情况下工作......我想可能有更复杂的循环依赖,它无法处理。无论如何,当然,消除循环依赖是更可取的。
答案 1 :(得分:5)
回答第一个问题“如何使用Guice实例化实例A”:您只需将@Inject
添加到构造函数中:
class A {
private final B b;
@Inject
A() {
this.b = new B(this);
}
}
这是有效的,因为用于创建A
的API没有循环依赖关系。只要需要创建或注入A
对象,Guice就会使用A
构造函数。
如果您的问题是如何使用Guice创建一个用于创建对象的API具有循环依赖关系的对象,请参阅this blog post by Misko Hevery(如Yury的答案中所述)。
答案 2 :(得分:4)
答案是在代码中存在循环依赖时不应使用依赖注入框架。
因此,您必须事先重构代码。据我所知,紧耦合类有两种解决方案:将两个类合并为一个或引入新类并将常用逻辑移入其中(详细看here)
答案 3 :(得分:3)
我认为NamshubWriter的提议并不是很有价值。我认为在Guice中,构造函数应该完成一件事:将参数分配到字段中。如果您还需要做任何其他事情,请将其放入工厂或提供商处。
在这种情况下,我们需要A的提供者。提供者可以直接调用新的B(),但是我们直接将A连接到B,这是我们首先想要避免的。所以我们间接在工厂上创建B,guice可以通过assistedInject为我们提供。此代码运行并编译良好,并完全解耦A和B.
在实际场景中,您需要隐藏接口后面的A和B以利用分离。
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.FactoryProvider;
public class Try {
public static void main(String[] args) {
System.out.println(
Guice.createInjector(new MyModule()).getInstance(A.class)
);
}
}
class MyModule extends AbstractModule {
public void configure() {
bind(A.class).toProvider(AProvider.class);
bind(IBFactory.class).toProvider(
FactoryProvider.newFactory(IBFactory.class, B.class));
}
}
class A {
B b;
public void setB(B b) {
this.b = b;
}
}
class B {
A a;
@Inject
B(@Assisted A a) {
this.a = a;
}
}
class AProvider implements Provider<A> {
private final IBFactory bFactory;
@Inject
AProvider(IBFactory bFactory) {
this.bFactory = bFactory;
}
public A get() {
A a = new A();
a.setB(bFactory.create(a));
return a;
}
}
interface IBFactory {
public B create(A a);
}