依赖注入:按区域划分(Guice,Spring,Whatever) [英] Dependency injection: Scoping by region (Guice, Spring, Whatever)

查看:447
本文介绍了依赖注入:按区域划分(Guice,Spring,Whatever)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我需要的简化版本。

Here's a simplified version of my needs.

我有一个程序,其中每个B对象都有自己的C和D对象,通过Guice注入。另外,A对象被注入每个C和D对象。

I have a program where every B object has its own C and D object, injected through Guice. In addition an A object is injected into every C and D objects.

我想要的是:对于每个B对象,它的C和D对象将被注入同一个A对象。

What I want: that for each B object, its C and D objects will be injected with the same A object.

(1)Guice支持singleton和原型模式。然而,我需要的是它之间的东西:我需要一个单一的WRT给一个给定的B对象(这样C和D注入一个B对象将共享一个A对象)。对于另一个B对象,我想要另一个A.所以这是一个单例,但是对于程序的有限范围(实际上是数据结构的有限范围)。

(1) Guice supports "singleton" and "prototype" modes. However, what I need is something in between: I need A to be singleton WRT to a given B object (so that the C and D injected into a B object will share an A object). For another B object, I want another A. So it's a singleton but for a limited scope of the program (actually, a limited scope of a data structure).

2)我不介意使用方法(setter)或字段注入的解决方案。

(2) I don't mind a solution that uses method (setter)- or field- injection.

(3)我尝试了几次,以实现这一点总是觉得我只需要实现DI容器的一些自定义的东西来使这项工作 - 但它从来没有奏效。因此,我正在寻找一个详细的解决方案(不只是挥手)

(3) I tried, several times, to achieve this and it always felt that I only need to implement some custom thingy of the DI container to make this work - but it never worked. Thus, I am looking for a detailed solution (not just "hand waving")

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

Specifically, I want the output of the program (below) to be:

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容器的)解决方案。

I am expecting DI containers to allow this kind of customization but so far I had no luck in finding a solution. Below is my Guice-based code, but a Spring-based (or other DI containers-based) solution is welcome.

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


推荐答案

一个解决方案基于您的原始代码 - 有三个变化:

Here's one solution based on your original code - there are three changes:


  1. 将A,C和D的绑定移动到单独的子模块

  2. 将A标记为子模块中的单例

  3. 在主模块中使用@Provides方法为BImpl提供< br>
    a每个请求的新的子注入器 - 这是子模块进入的位置

这是因为单例绑定A现在仅限于每个子注射器。

This works because the singleton binding for A is now limited to each child injector.

[注意:您可以随时将子模块实例缓存在

的字段中主要模块,如果你不想继续创建它的每一个请求的B]

[ Note: you could always cache the sub-module instance in a field of the
main-module if you don't want to keep creating it for each request of B ]

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

这篇关于依赖注入:按区域划分(Guice,Spring,Whatever)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆