在我看来,你需要为每个RootObject
及其所有依赖项的实例设置一个范围。
在吉斯您可以创建一个自定义的范围,说@ObjectScoped
,像这样:
@Target({ TYPE, METHOD })
@Retention(RUNTIME)
@ScopeAnnotation
public @interface ObjectScoped {}
现在只需将RootObject
,A
,B
和D
到这个范围:
@ObjectScoped
public class RootObject {
private A a;
private B b;
@Inject
public RootObject(A a, B b) {
this.a = a;
this.b = b;
}
public A getA() {
return a;
}
public B getB() {
return b;
}
}
@ObjectScoped
public class A {
private D d;
@Inject
public A(D d) {
this.d = d;
}
public D getD() {
return d;
}
}
// The same for B and D
现在每个RootObject
都有其自己的范围。您可以实现此作为一个简单的HashMap
:
public class ObjectScope {
private Map<Key<?>,Object> store = new HashMap<Key<?>,Object>();
@SuppressWarnings("unchecked")
public <T> T get(Key<T> key) {
return (T)store.get(key);
}
public <T> void set(Key<T> key, T instance) {
store.put(key, instance);
}
}
整合这些示波器与吉斯,您将需要一个com.google.inject.Scope
- 实施它可以让你切换范围,并在您Module
相应的线路。
public class GuiceObjectScope implements Scope {
// Make this a ThreadLocal for multithreading.
private ObjectScope current = null;
@Override
public <T> Provider<T> scope(final Key<T> key, final Provider<T> unscoped) {
return new Provider<T>() {
@Override
public T get() {
// Lookup instance
T instance = current.get(key);
if (instance==null) {
// Create instance
instance = unscoped.get();
current.set(key, instance);
}
return instance;
}
};
}
public void enter(ObjectScope scope) {
current = scope;
}
public void leave() {
current = null;
}
}
public class ExampleModule extends AbstractModule {
private GuiceObjectScope objectScope = new GuiceObjectScope();
@Override
protected void configure() {
bindScope(ObjectScoped.class, objectScope);
// your bindings
}
public GuiceObjectScope getObjectScope() {
return objectScope;
}
}
初始化你的程序是这样的:
ExampleModule module = new ExampleModule();
Injector injector = Guice.createInjector(module);
GuiceObjectScope objectScope = module.getObjectScope();
创建的RootObject
第一个实例和其对应的范围:
ObjectScope obj1 = new ObjectScope();
objectScope.enter(obj1);
RootObject rootObject1 = injector.getInstance(RootObject.class);
objectScope.leave();
只需切换范围为第二组对象:
ObjectScope obj2 = new ObjectScope();
objectScope.enter(obj2);
RootObject rootObject2 = injector.getInstance(RootObject.class);
objectScope.leave();
测试,如果你的要求得到满足:
assert rootObject1 != rootObject2;
assert rootObject1.getA() != rootObject2.getA();
assert rootObject1.getA().getD() == rootObject1.getB().getD();
assert rootObject1.getA().getD() != rootObject2.getB().getD();
要使用一组对象的工作刚刚进入其范围和使用注射器:
objectScope.enter(obj1);
B b1 = injector.getInstance(B.class);
objectScope.leave();
assert rootObject1.getB() == b1;
我有一个想法,@Assisted注射可以在这里使用,但我无法确切地看到它应该如何使用... – Rich 2012-03-30 12:42:44
@Josh:哪里的实况说远离示波器? – 2012-07-30 07:23:33
@ A.H。,http://code.google.com/p/google-guice/wiki/CustomScopes - 第一行。 “通常建议用户不要编写自己的自定义作用域 - 内置作用域应该足以满足大多数应用程序的需求。”我发现第一种方法很好 - 根据需要创建儿童注射器。我们只需要小心,“每个组的单身人士”不会意外地在父注射器中受到束缚,但这很容易检查。 – Josh 2012-07-31 17:39:00