Java 依赖注入:按区域(Guice、Spring等)确定范围

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

这是我的需求的简化版本

我有一个程序,其中每个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容器的一些定制内容就可以实现这一点,但它从来没有起过作用。因此,我正在寻找一个详细的解决方案(不仅仅是“挥手”)

[编辑结束]

具体来说,我希望程序(如下)的输出为:

其当前产生以下输出:

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);    
        }  
      }