Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/google-app-engine/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Dependency injection 使用具有循环依赖项的Guice_Dependency Injection_Guice - Fatal编程技术网

Dependency injection 使用具有循环依赖项的Guice

Dependency injection 使用具有循环依赖项的Guice,dependency-injection,guice,Dependency Injection,Guice,考虑这个简单的例子 Class A { B b; A() { this.b = new B(this); } } 在本例中,实例A了解实例B,实例B了解实例A 我的问题是:如何用Guice实例化实例A,即如何让Guice处理这个复杂的循环依赖关系?答案是,当代码中存在循环依赖关系时,不应该使用依赖注入框架 因此,您必须事先重构代码。据我所知,紧密耦合类有两种解决方案:要么将两个类合并为一个类,要么引入新类并将公共逻辑移到其中(以查看细节)回答第一个问题“如何使用

考虑这个简单的例子

Class A {
   B b;
   A() {
       this.b = new B(this);
   }
}
在本例中,实例A了解实例B,实例B了解实例A


我的问题是:如何用Guice实例化实例A,即如何让Guice处理这个复杂的循环依赖关系?

答案是,当代码中存在循环依赖关系时,不应该使用依赖注入框架


因此,您必须事先重构代码。据我所知,紧密耦合类有两种解决方案:要么将两个类合并为一个类,要么引入新类并将公共逻辑移到其中(以查看细节)

回答第一个问题“如何使用Guice实例化实例”:您可以简单地将
@Inject
添加到构造函数中:

class A {
   private final B b;

   @Inject
   A() {
       this.b = new B(this);
   }
}
这是因为用于创建
A
的API没有循环依赖关系。Guice只要在需要创建或注入
A
对象时使用
A
构造函数即可


如果您的问题是如何使用Guice创建一个对象,而用于创建该对象的API具有循环依赖关系,请参阅(如Yury的回答中所述)。

您的示例根本不是问题,因为您直接构建的是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也可以处理这种注入(通过代理)。这在这样一个简单的情况下无论如何都是有效的。。。我想可能有更复杂的循环依赖关系,它无法处理。无论如何,消除循环依赖当然更可取。

我认为NamshubWriter的建议不太靠谱。我认为在Guice中,构造函数应该只做一件事:将参数分配到字段中。如果您还需要做其他事情,请将其投入工厂或供应商

在本例中,我们需要为a提供一个提供程序。该提供程序可以直接调用new 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);
}
import com.google.inject.AbstractModule;
导入com.google.inject.Guice;
导入com.google.inject.inject;
导入com.google.inject.Provider;
导入com.google.inject.assistedinject.Assisted;
导入com.google.inject.assistedinject.FactoryProvider;
公务舱试驾{
公共静态void main(字符串[]args){
System.out.println(
createInjector(新的MyModule()).getInstance(A.class)
);
}
}
类MyModule扩展了AbstractModule{
public void configure(){
绑定(A.class).toProvider(A.class.);
绑定(IBFactory.class).toProvider(
FactoryProvider.newFactory(IBFactory.class,B.class));
}
}
甲级{
B B;
公屋空置登记册(乙){
这个.b=b;
}
}
B类{
A A;
@注入
B(@A){
这个a=a;
}
}

类AProvider实现提供程序

您可以简单地将@Inject添加到A的构造函数中。我猜您的实际类要复杂一些。B是接口吗?除了注射疫苗,它还需要注射什么吗?顺便说一句,让“this”字段转义给构造函数通常是个坏主意。不,B不是接口,而是类。当然,循环依赖性并不好,我可以重构这两个类,但我真正需要的是理解Guice的可行性。对于无参数构造函数,甚至不需要@Inject。这与Yury的代码完全相同。@Inject无效,代码也不会从B中解包A,B是guice的全部要点。是的,这与OP编写的代码相同(使用@Inject可以更清楚地表明guice使用了构造函数)。关键是API中没有循环依赖关系,所以Guice可以创建一个循环。这个设计是否是一个好的设计是另一个问题。你可以在我对OP的评论中看到我的一些担忧,OP同意循环依赖是个坏主意。这只适用于单例。一般情况如何?关于注射后的情况有什么想法吗?同意尤里的说法。使用DI的循环依赖会导致痛苦。