Guice proxying to support circular dependency

后端 未结 3 1279
伪装坚强ぢ
伪装坚强ぢ 2021-02-19 20:40

I\'m getting the following error in my code at launch:

Tried proxying com.bar.Foo to support a circular dependency, but it is not an interface.

3条回答
  •  别那么骄傲
    2021-02-19 21:22

    I'm new to this concept, but here's my understanding.

    Let's say you have interfaces A and B, and implementations Ai and Bi.

    If Ai has a dependency on B, and Bi has a dependency on A, then Guice can create a proxy implementation of A (call it Ap) that will at some point in the future be given an Ai to delegate to. Guice gives that Ap to Bi for its dependency on A, allowing Bi to finish instantiation. Then, since Bi has been instantiated, Guice can instantiate Ai with Bi. Then, since Ai is now good to do, Guice tells Ap to delegate to Ai.

    If A and B were not interfaces (and you just had Ai and Bi) this just would not be possible, because creating Ap would require you to extend Ai, which already needs a Bi.

    Here's what it might look like with code:

    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() {
       }
    }
    

    The proxy class that Guice makes would look like this:

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

    And it would all be wired using this basic idea:

    Ap proxyA = new Ap();
    B b = new B(proxyA);
    A a = new A(b);
    proxyA.setDelegate(a);
    

    And here's what it would be like if you only had Ai and Bi, without interfaces A and B.

    public class Ap extends Ai {
        private Ai delegate;
    
        public Ap() {
           super(_); //a B is required here, but we can't give one!
        }
    }
    

    If I just throw enough classes behind interfaces, will everything be fine?

    I would guess that there are strict restrictions on how the proxy can be interacted with in the constructor. In other words, if B tries to call A before Guice has had a chance to populate A's proxy with the real A, then I would expect a RuntimeException.

提交回复
热议问题