Guice代理支持循环依赖

Nic*_*ner 11 java dependency-injection guice

我在启动时的代码中遇到以下错误:

尝试代理com.bar.Foo来支持循环依赖,但它不是一个接口.

这种代理究竟是如何工作的?如果我只是在接口后面抛出足够的类,一切都会好吗?

(我知道循环依赖通常是代码味道,但我认为在这种情况下它是可以的.)

Jan*_*ski 10

虽然"注入接口"方法是完全有效的,甚至在某些情况下甚至可能是更好的解决方案,但一般来说,您可以使用更简单的解决方案:提供商.

对于每个级别"A"guice可以管理,guice也提供" Provider<A>".这是javax.inject.Provider接口的内部实现,其get()消息将为" return injector.getInstance(A.class)".你不必自己实现界面,它是"guice magic"的一部分.

因此,您可以将A-> B,BA示例缩短为:

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);
}}
Run Code Online (Sandbox Code Playgroud)

我更喜欢这个,因为它更具可读性(你不会因为构造函数已经拥有"B"的实例而感到愚蠢)并且由于你可以自己实现提供者,它仍然可以在guice上下文之外"手动"工作(用于测试例如).


Mar*_*ers 9

我是这个概念的新手,但这是我的理解.

比方说,你有接口AB,并实现AiBi.

如果Ai依赖于B,并且Bi具有依赖性A,那么Guice可以创建A(调用它Ap)的代理实现,该代理实现将在将来的某个时刻被赋予Ai委托.吉斯给出了ApBi其上的依赖A,从而Bi完成实例化.然后,因为Bi已被实例化,吉斯实例可以AiBi.然后,由于Ai现在好了,Guice告诉Ap代表Ai.

如果A并且B不是接口(并且你只是AiBi),这就不可能,因为创建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() {
   }
}
Run Code Online (Sandbox Code Playgroud)

Guice制作的代理类如下所示:

public class Ap implements A {
    private A delegate;
    void setDelegate(A a) {
        delegate = a;
    }

    public void doA() {
        delegate.doA();
    }
}
Run Code Online (Sandbox Code Playgroud)

它将全部使用这个基本想法连线:

Ap proxyA = new Ap();
B b = new B(proxyA);
A a = new A(b);
proxyA.setDelegate(a);
Run Code Online (Sandbox Code Playgroud)

如果你只有,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!
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我只是在接口后面抛出足够的类,一切都会好吗?

我猜想在构造函数中如何与代理进行交互有严格的限制.换句话说,如果B试图在Guice有机会用真实A填充A的代理之前调用A,那么我会期望一个RuntimeException.