Java 依赖注入:按区域(Guice、Spring等)确定范围
这是我的需求的简化版本 我有一个程序,其中每个B对象都有自己的C和D对象,通过Guice注入。此外,一个A对象被注入到每个C和D对象中 我想要的是:对于每个B对象,它的C和D对象将被注入相同的A对象 [编辑开始] (1) Guice支持“单例”和“原型”模式。然而,我需要的是介于两者之间的东西:我需要A是给定B对象的单例WRT(这样注入B对象的C和D将共享A对象)。对于另一个B对象,我想要另一个A。所以它是一个单例,但对于程序的有限范围(实际上,数据结构的有限范围) (2) 我不介意使用方法(setter)或字段注入的解决方案 (3) 我尝试了好几次来实现这一点,它总是觉得我只需要实现DI容器的一些定制内容就可以实现这一点,但它从来没有起过作用。因此,我正在寻找一个详细的解决方案(不仅仅是“挥手”) [编辑结束] 具体来说,我希望程序(如下)的输出为: 其当前产生以下输出:Java 依赖注入:按区域(Guice、Spring等)确定范围,java,spring,dependency-injection,guice,Java,Spring,Dependency Injection,Guice,这是我的需求的简化版本 我有一个程序,其中每个B对象都有自己的C和D对象,通过Guice注入。此外,一个A对象被注入到每个C和D对象中 我想要的是:对于每个B对象,它的C和D对象将被注入相同的A对象 [编辑开始] (1) Guice支持“单例”和“原型”模式。然而,我需要的是介于两者之间的东西:我需要A是给定B对象的单例WRT(这样注入B对象的C和D将共享A对象)。对于另一个B对象,我想要另一个A。所以它是一个单例,但对于程序的有限范围(实际上,数据结构的有限范围) (2) 我不介意使用方法(s
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]
使用[A0]创建C0
使用[A1]PrivateModule和/或作用域创建D0可能会有所帮助,但我不确定。如果没有,您可能必须为a对象编写自定义提供程序。不确定Guice,但Spring对此没有问题,例如singleton(默认情况下只创建了一个实例)、prototype(每次引用它时都会创建一个新的bean实例),等等
例如,以下XML配置将产生一个Foo
实例和三个Bar
实例
<bean id="Foo" class="com.name.Foo"/>
<bean id="Bar1" class="com.name.Bar">
<property name="foo" ref="Foo"/>
</bean>
<bean id="Bar2" class="com.name.Bar">
<property name="foo" ref="Foo"/>
</bean>
<bean id="Bar3" class="com.name.Bar">
<property name="foo" ref="Foo"/>
</bean>
与@Singleton注释类似。import java.util.*;
import java.util.*;
import com.google.inject.*;
import com.google.inject.name.*;
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() {
CachingScope cachedScope = new CachingScope();
bind(C.class).to(CImpl.class);
bind(D.class).to(DImpl.class);
bind(B.class).to(BImpl.class).in(new ClearingScope(cachedScope));
bind(A.class).to(AImpl.class).in(cachedScope);
}
}
public static class CachingScope implements Scope {
List<CacheProvider<?>> providers = new LinkedList<CacheProvider<?>>();
public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
CacheProvider<T> t = new CacheProvider<T>(unscoped);
providers.add(t);
return t;
}
public void clear() {
for(CacheProvider c : providers) {
c.clear();
}
}
}
public static class ClearingScope implements Scope {
CachingScope scopeToClear;
ClearingScope(CachingScope scopeToClear) {
this.scopeToClear = scopeToClear;
}
public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
return new ClearingProvider<T>(unscoped, scopeToClear);
}
}
public static class CacheProvider<T> implements Provider<T> {
T t;
Provider<T> unscoped;
CacheProvider(Provider<T> unscoped) {
this.unscoped = unscoped;
}
public T get() {
if(t == null) {
t = unscoped.get();
}
return t;
}
public void clear() {
t = null;
}
}
public static class ClearingProvider<T> implements Provider<T> {
Provider<T> unscoped;
CachingScope scopeToClear;
ClearingProvider(Provider<T> unscoped, CachingScope scopeToClear) {
this.unscoped = unscoped;
this.scopeToClear = scopeToClear;
}
public T get() {
scopeToClear.clear();
return unscoped.get();
}
}
public static void main(String[] args) {
Injector inj = Guice.createInjector(new MyModule());
inj.getInstance(B.class);
System.out.println("--");
inj.getInstance(B.class);
}
}
导入com.google.inject.*;
导入com.google.inject.name.*;
公共班机{
公共静态类超级{
私有静态映射,整数>();
私有整数值;
公共超级(对象…参数){
value=map.get(getClass());
value=value==null?0:+value;
put(getClass(),value);
如果(args.length>0)
System.out.println(“创建的”+this+”和“+Arrays.toString(args));
}
@凌驾
公共最终字符串toString(){
返回“+getClass().getSimpleName().charAt(0)+值;
}
}
公共接口A{}
公共静态类AImpl extensed Super实现了一个{}
公共接口B{}
公共静态类BImpl扩展了超级实现B{
@注入公共BImpl(cc,dd){super(C,D);}
}
公共接口C{}
公共静态类CImpl扩展了超级C{
@注入公共CImpl(A){super(A);}
}
公共接口D{}
公共静态类DImpl扩展了超级实现D{
@注入公共DImpl(A){super(A);}
}
公共静态类MyModule扩展了AbstractModule{
@凌驾
受保护的void configure(){
CachingScope cachedScope=新CachingScope();
绑定(C.class).to(CImpl.class);
绑定(D.class).to(DImpl.class);
绑定(B.class).to(BImpl.class).in(新的ClearingScope(cachedScope));
绑定(A.class).to(AImpl.class).in(cachedScope);
}
}
公共静态类CachingScope实现作用域{
列表>();
公共提供程序作用域(键、提供程序未作用域){
CacheProvider t=新的CacheProvider(未范围);
增加(t);
返回t;
}
公共空间清除(){
for(缓存提供程序c:提供程序){
c、 清除();
}
}
}
公共静态类ClearingScope实现作用域{
卡钦斯镜清洁镜;
清理镜(清理镜范围){
this.scopeToClear=scopeToClear;
}
公共提供程序作用域(键、提供程序未作用域){
返回新的ClearingProvider(无范围、scopeToClear);
}
}
公共静态类CacheProvider实现提供程序{
T;
供应商不受限制;
CacheProvider(提供程序不受范围限制){
this.unscoped=unscoped;
}
公共部门得不到{
如果(t==null){
t=unscoped.get();
}
返回t;
}
公共空间清除(){
t=零;
}
}
公共静态类ClearingProvider实现提供程序{
供应商不受限制;
卡钦斯镜清洁镜;
ClearingProvider(提供程序无范围,CachingScope scopeToClear){
this.unscoped=unscoped;
this.scopeToClear=scopeToClear;
}
公共部门得不到{
scopeToClear.clear();
返回unscoped.get();
}
}
公共静态void main(字符串[]args){
Injector inj=Guice.createInjector(新的MyModule());
inj.getInstance(B.class);
System.out.println(“--”);
inj.getInstance(B.class);
}
}
嗯,这在API中是一个有趣的游戏。我不太喜欢这个解决方案,但我认为它是可行的。现在有两个新的作用域,一个CachingScope,可以很好地缓存结果。还有一个清除作用域,当它需要一个新对象时,可以清除缓存。不知道这个解决方案有多健壮,我想对于需要注入Bs的Bs来说,这个解决方案可能不是很好。
我有点惊讶,我不能用这样的东西来处理儿童注射器,但有时我会有点笨。我不熟悉guice,只熟悉spring。我认为不可能配置DI引擎来实现您试图实现的目标。我看到了两种解决方案:
使B对象依赖于(A、C、D),并在运行时将A注入C和D
使B仅依赖于A,而A依赖于C和D
你考虑过改变你的设计吗
<bean id="Foo" class="com.name.Foo"/>
<bean id="Bar1" class="com.name.Bar">
<property name="foo" ref="Foo"/>
</bean>
<bean id="Bar2" class="com.name.Bar">
<property name="foo" ref="Foo"/>
</bean>
<bean id="Bar3" class="com.name.Bar">
<property name="foo" ref="Foo"/>
</bean>
<bean id="Foo" class="com.name.Foo" scope="prototype" />
<bean id="Bar1" class="com.name.Bar">
<property name="foo" ref="Foo"/>
</bean>
<bean id="Bar2" class="com.name.Bar">
<property name="foo" ref="Foo"/>
</bean>
<bean id="Bar3" class="com.name.Bar">
<property name="foo" ref="Foo"/>
</bean>
import java.util.*;
import com.google.inject.*;
import com.google.inject.name.*;
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() {
CachingScope cachedScope = new CachingScope();
bind(C.class).to(CImpl.class);
bind(D.class).to(DImpl.class);
bind(B.class).to(BImpl.class).in(new ClearingScope(cachedScope));
bind(A.class).to(AImpl.class).in(cachedScope);
}
}
public static class CachingScope implements Scope {
List<CacheProvider<?>> providers = new LinkedList<CacheProvider<?>>();
public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
CacheProvider<T> t = new CacheProvider<T>(unscoped);
providers.add(t);
return t;
}
public void clear() {
for(CacheProvider c : providers) {
c.clear();
}
}
}
public static class ClearingScope implements Scope {
CachingScope scopeToClear;
ClearingScope(CachingScope scopeToClear) {
this.scopeToClear = scopeToClear;
}
public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
return new ClearingProvider<T>(unscoped, scopeToClear);
}
}
public static class CacheProvider<T> implements Provider<T> {
T t;
Provider<T> unscoped;
CacheProvider(Provider<T> unscoped) {
this.unscoped = unscoped;
}
public T get() {
if(t == null) {
t = unscoped.get();
}
return t;
}
public void clear() {
t = null;
}
}
public static class ClearingProvider<T> implements Provider<T> {
Provider<T> unscoped;
CachingScope scopeToClear;
ClearingProvider(Provider<T> unscoped, CachingScope scopeToClear) {
this.unscoped = unscoped;
this.scopeToClear = scopeToClear;
}
public T get() {
scopeToClear.clear();
return unscoped.get();
}
}
public static void main(String[] args) {
Injector inj = Guice.createInjector(new MyModule());
inj.getInstance(B.class);
System.out.println("--");
inj.getInstance(B.class);
}
}
public static class MyModule extends AbstractModule {
@Override
protected void configure() {
bind(A.class).to(AImpl.class);
}
@Provides
protected B provideB(A a) {
C c = new CImpl(a);
D d = new DImpl(a);
return new BImpl(c, d);
}
}
public static class MyOtherModule extends PrivateModule {
private final Annotation annotation;
public MyOtherModule(Annotation annotation) {
this.annotation = annotation;
}
@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);
bind(B.class).annotatedWith(annotation).to(BImpl.class);
expose(B.class).annotatedWith(annotation);
}
}
public static void main(String[] args) {
Injector inj = Guice.createInjector(new MyOtherModule(Names.named("first")),
new MyOtherModule(Names.named("second")));
inj.getInstance(Key.get(B.class, Names.named("first")));
inj.getInstance(Key.get(B.class, Names.named("second")));
}
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);
}
}