Guice 代理以支持循环依赖关系
我在启动时在代码中收到以下错误:
尝试代理com.bar.Foo来支持循环依赖,但它不是一个接口。
此代理究竟是如何工作的?如果我只是在接口后面抛出足够的类,一切都会好起来吗?
(我知道循环依赖关系通常是一种代码气味,但我认为在这种情况下没关系。
我在启动时在代码中收到以下错误:
尝试代理com.bar.Foo来支持循环依赖,但它不是一个接口。
此代理究竟是如何工作的?如果我只是在接口后面抛出足够的类,一切都会好起来吗?
(我知道循环依赖关系通常是一种代码气味,但我认为在这种情况下没关系。
虽然“注入接口”方法完全有效,在某些情况下甚至可能是更好的解决方案,但通常,您可以使用更简单的解决方案:提供程序。
对于每个类“A”guice可以管理,guice还提供了一个“”。这是 javax.inject.Provider-interface 的内部实现,其消息将 “”。您不必自己实现接口,这是“guice magic”的一部分。Provider<A>
get()
return injector.getInstance(A.class)
因此,您可以将 A->B,B-A 示例缩短为:
public class CircularDepTest {
static class A {
private final Provider<B> b;
private String name = "A";
@Inject
public A(Provider<B> b) {
this.b = b;
}
}
static class B {
private final Provider<A> a;
private String name = "B";
@Inject
public B(Provider<A> a) {
this.a = a;
}
}
@Inject
A a;
@Inject
B b;
@Before
public void setUp() {
Guice.createInjector().injectMembers(this);
}
@Test
public void testCircularInjection() throws Exception {
assertEquals("A", a.name);
assertEquals("B", a.b.get().name);
assertEquals("B", b.name);
assertEquals("A", b.a.get().name);
}}
我更喜欢这个,因为它更具可读性(你不会被愚弄相信构造函数已经持有“B”的实例),并且由于您可以自己实现提供者,因此它仍然可以在guice上下文之外“手动”工作(例如用于测试)。
我对这个概念很陌生,但这是我的理解。
假设您有接口和 、、实现和 。A
B
Ai
Bi
如果对 有依赖关系,并且对 有依赖关系,那么 Guice 可以创建一个代理实现(调用它),该实现将在将来的某个时候被赋予一个委托给。Guice 给出了它依赖于 ,允许完成实例化。然后,由于已经实例化,Guice 可以使用 实例化。然后,既然现在是好的,Guice告诉委托给.Ai
B
Bi
A
A
Ap
Ai
Ap
Bi
A
Bi
Bi
Ai
Bi
Ai
Ap
Ai
如果 和 不是接口(并且您刚刚拥有和),这将是不可能的,因为创建将需要扩展,这已经需要一个.A
B
Ai
Bi
Ap
Ai
Bi
以下是代码的外观:
public interface A {
void doA();
}
public interface B {
void doB();
}
public class Ai implements A {
private final B b;
@Inject
public Ai(B b) {
this.b = b;
}
public void doA() {
b.doB();
}
}
public class Bi implements B {
private final A a;
@Inject
public Bi(A a) {
this.a = a;
}
public void doB() {
}
}
Guice 创建的代理类将如下所示:
public class Ap implements A {
private A delegate;
void setDelegate(A a) {
delegate = a;
}
public void doA() {
delegate.doA();
}
}
这一切都将使用以下基本思想进行连接:
Ap proxyA = new Ap();
B b = new B(proxyA);
A a = new A(b);
proxyA.setDelegate(a);
如果您只有 和 ,没有接口和 ,情况会是这样的。Ai
Bi
A
B
public class Ap extends Ai {
private Ai delegate;
public Ap() {
super(_); //a B is required here, but we can't give one!
}
}
如果我只是在接口后面抛出足够的类,一切都会好起来吗?
我猜想在构造函数中如何与代理交互有严格的限制。换句话说,如果B试图在Guice有机会用真正的A填充A的代理之前调用A,那么我会期待一个运行时Exception。