当前位置: 首页 > 面试题库 >

依赖注入:按区域划分范围(Guice,Spring,无论如何)

金伟
2023-03-14
问题内容

这是我的需求的简化版本。

我有一个程序,其中每个B对象都有通过Guice注入的自己的C和D对象。另外,将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 [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);    
    }  
  }

问题答案:

这是一个基于原始代码的解决方案-进行了三处更改:

  1. 将A,C和D的绑定移到单独的子模块中
  2. 在子模块中将A标记为单例
  3. 在主模块中使用@Provides方法为BImpl的实例提供
    每个请求的新子注入器-这是子模块所在的位置

之所以可行,是因为A的单例绑定现在仅限于每个子注入器。

[注意:
如果您不想一直为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);    
    }  
  }


 类似资料:
  • 问题内容: 我的团队正在研究依赖项注入框架,并试图在使用Google-Guice和PicoContainer之间做出选择。 我们正在寻找框架中的几件事情: 较小的代码占用空间-我的意思是较小的代码占用空间是我们不想在我们的代码库中到处都有依赖项注入代码垃圾。如果我们需要在将来进行重构,我们希望它尽可能简单。 性能-创建和注入对象时,每个框架有多少开销? 易于使用-学习曲线是否很大?我们是否必须编写

  • 我已经使用GoogleGuice几个月了。我对它很满意,但似乎我用错了。我创造了很多辅助注射,有时还有两个注射器。 因此,我想了解这里的一般原则。 是否应该为连接主类所有内容的所有应用程序配备一个喷油器? 最佳实践是关于从应用程序一开始就尝试在构造函数中注入大量内容吗?(我看到了测试的优势) 我的主要问题是,有时我觉得某些对象组的创建属于某个组件。有必要封装它吗?你会如何处理? 当您拥有一个重要的

  • 我已经对Spring bean使用的注释进行了注释。我通过spring DI成功地创建了相同的bean,并设置了对象注入的范围。现在,我想用Struts2和di做同样的事情。为此,我在中创建了bean定义 和简单的操作来创建bean并将其注入到我的操作中 在JSP中,我在会话bean上使用简单的迭代器 null

  • 我遇到了依赖注入周期问题。我请求重新设计建议。提前谢谢。 错误描述:应用程序上下文中某些bean的依赖关系形成一个循环: 这是两个班 第一类: 第二类:

  • 我有一个非常简单的场景可以使用 DI 解决,但我无法找到合适的示例/文档来帮助我完成。我是Scala/Guice世界的新手。 当前组件看起来像这样 现在,我在Foo和Bar之间有一个依赖项。所以,通常代码看起来像这样 其中只是返回。当然,为了简洁起见,我删除了工厂/助手。 我意识到,当我使用“new”时,这已经脱离了DI范式。我希望确保可以基于参数将Bar注入FooImpl。有点像使用工厂。我们如

  • 我想在使用guice实例化子类时,将依赖项注入父类。在下面的示例中,我试图创建的一个实例,同时希望能够在运行时使用Guice注入。我该怎么做?