这是我的需求的简化版本。
我有一个程序,其中每个 B 对象都有自己的 C 和 D 对象,通过 Guice 注入(inject)。此外,一个 A 对象被注入(inject)到每个 C 和 D 对象中。
我想要什么:对于每个 B 对象,它的 C 和 D 对象将被注入(inject)相同的 A 对象。
[编辑-开始]
(1) Guice 支持“单例”和“原型(prototype)”模式。但是,我需要的是介于两者之间的东西:我需要 A 成为给定 B 对象的单例 WRT(以便注入(inject) B 对象的 C 和 D 将共享一个 A 对象)。对于另一个 B 对象,我想要另一个 A。所以它是一个单例,但适用于程序的有限范围(实际上是数据结构的有限范围)。
(2) 我不介意使用方法(setter)或字段注入(inject)的解决方案。
(3) 我曾多次尝试实现这一目标,但总觉得我只需要实现 DI 容器的一些自定义事物即可完成这项工作 - 但它从未奏效。因此,我正在寻找一个详细的解决方案(不仅仅是“挥手”)
[编辑结束]
具体来说,我希望程序的输出(如下)是:
Created C0 with [A0]
Created D0 with [A0]
Created B0 with [C0, D0]
Created C1 with [A1]
Created D1 with [A1]
Created B1 with [C1, D1]
它目前在哪里产生以下输出:
Created C0 with [A0]
Created D0 with [A1] <-- Should be A0
Created B0 with [C0, D0]
Created C1 with [A2] <-- Should be A1
Created D1 with [A3] <-- Should be A1
Created B1 with [C1, D1]
我期待 DI 容器允许这种自定义,但到目前为止我还没有找到解决方案。下面是我基于 Guice 的代码,但欢迎使用基于 Spring(或其他基于 DI 容器)的解决方案。
import java.util.Arrays;
import com.google.inject.*;
public class Main {
public static class Super {
private static Map<Class<?>,Integer> map = new HashMap<Class<?>,Integer>();
private Integer value;
public Super(Object... args) {
value = map.get(getClass());
value = value == null ? 0 : ++value;
map.put(getClass(), value);
if(args.length > 0)
System.out.println("Created " + this + " with " + Arrays.toString(args));
}
@Override
public final String toString() {
return "" + getClass().getSimpleName().charAt(0) + value;
}
}
public interface A { }
public static class AImpl extends Super implements A { }
public interface B { }
public static class BImpl extends Super implements B {
@Inject public BImpl(C c, D d) { super(c,d); }
}
public interface C { }
public static class CImpl extends Super implements C {
@Inject public CImpl(A a) { super(a); }
}
public interface D { }
public static class DImpl extends Super implements D {
@Inject public DImpl(A a) { super(a); }
}
public static class MyModule extends AbstractModule {
@Override
protected void configure() {
bind(A.class).to(AImpl.class);
bind(B.class).to(BImpl.class);
bind(C.class).to(CImpl.class);
bind(D.class).to(DImpl.class);
}
}
public static void main(String[] args) {
Injector inj = Guice.createInjector(new MyModule());
inj.getInstance(B.class);
inj.getInstance(B.class);
}
}
最佳答案
这是基于您的原始代码的一种解决方案 - 有三个更改:
- 将 A、C 和 D 的绑定(bind)移动到单独的子模块中
- 将 A 标记为子模块中的单例
- 在主模块中使用@Provides 方法为BImpl 提供实例
每个请求都有一个新的子注入(inject)器 - 这是子模块的用武之地
这是可行的,因为 A 的单例绑定(bind)现在仅限于每个子注入(inject)器。
[注意:你总是可以将子模块实例缓存在
的字段中
如果您不想为 B 的每个请求继续创建 main-module ]
import java.util.*;
import com.google.inject.*;
public class Main {
public static class Super {
private static Map<Class<?>,Integer> map = new HashMap<Class<?>,Integer>();
private Integer value;
public Super(Object... args) {
value = map.get(getClass());
value = value == null ? 0 : ++value;
map.put(getClass(), value);
if(args.length > 0)
System.out.println("Created " + this + " with " + Arrays.toString(args));
}
@Override
public final String toString() {
return "" + getClass().getSimpleName().charAt(0) + value;
}
}
public interface A { }
public static class AImpl extends Super implements A { }
public interface B { }
public static class BImpl extends Super implements B {
@Inject public BImpl(C c, D d) { super(c,d); }
}
public interface C { }
public static class CImpl extends Super implements C {
@Inject public CImpl(A a) { super(a); }
}
public interface D { }
public static class DImpl extends Super implements D {
@Inject public DImpl(A a) { super(a); }
}
public static class MyModule extends AbstractModule {
@Override
protected void configure() {}
// >>>>>>>>
@Provides
B builder( Injector injector ) {
return injector.createChildInjector( new SubModule() ).getInstance( BImpl.class );
}
// <<<<<<<<
}
// >>>>>>>>
public static class SubModule extends AbstractModule {
@Override
protected void configure() {
bind(A.class).to(AImpl.class).in( Scopes.SINGLETON );
bind(C.class).to(CImpl.class);
bind(D.class).to(DImpl.class);
}
}
// <<<<<<<<
public static void main(String[] args) {
Injector inj = Guice.createInjector(new MyModule());
inj.getInstance(B.class);
inj.getInstance(B.class);
}
}
关于java - 依赖注入(inject) : Scoping by region (Guice, Spring,随便),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3014140/