【问题标题】:Guice : Inject an ArrayList of StringsGuice:注入字符串的 ArrayList
【发布时间】:2015-08-28 10:09:26
【问题描述】:

我正在尝试在 Guice 的帮助下注入 Strings 的 ArrayList。我想显示一个带有许多 RadioButtons 的面板(例如),用户可以在其中选择一些服务来激活。

一旦选择,我想获取所选服务的所有名称并将它们添加到列表中,并将此列表注入负责创建服务的经理。这是一个例子:

public class UIProviderModule extends ProviderServiceModule {
    private ArrayList<String> requestedServices;

    public UIProviderModule(ArrayList<String> requestedServices) {
        this.requestedServices = requestedServices;
    }

    @Override
    protected void configure() {
        bindConstant().annotatedWith(Names.named(Constants.REQ_SERVICES)).to(requestedServices);
        bind(IParser.class).to(UIParser.class);
        super.configure();
    }

}

我看过很多关于Multibindings 和Providers 的帖子,但我不明白这对我有什么帮助。我只想检索名称,因为我不使用必须绑定到接口的类。我错过了什么吗?

注意:我知道这可能不是使用 Guice 的好方法,因为我将列表绑定到 Module

【问题讨论】:

    标签: java arraylist guice inject


    【解决方案1】:

    这很容易做Guice:

    bind(new TypeLiteral<List<String>>() {})
        .annotatedWith(Names.named(Constants.REQ_SERVICES))
        .toInstance(requestedServices);
    

    请注意,为了绑定 List&lt;String&gt; 而不用 Java 擦除泛型,您需要创建一个短期匿名内部类型(TypeLiteral 的子类,其主体为空 {})。你也可以使用toInstance

    让模块接受用于绑定的参数并没有错,当所有绑定都可以轻松收集到一个地方时,我更喜欢使用多重绑定。

    请注意,您接受的 ArrayList&lt;String&gt; 是可变的,因此如果您将其注入多个地方,一位消费者可能会永久更改其他所有人的列表。使用 Guava 的 ImmutableList.copyOf(list)Collections.unmodifiableList(list) 可能更有意义(尽管如果模块创建者稍后更改传入的列表,后者仍然会让列表发生变化)。


    关于您提议的应用程序生命周期,请记住 Guice 的 绑定 在注入器创建后应该或多或少保持不变。您描述的生命周期可能有几种意义:

    • 在没有 Guice 帮助的情况下显示您的对话框,然后使用选定的选项创建一个注入器
    • 在所有选项中注入您的List&lt;String&gt;,显示对话框,然后传递列表
    • 使用所有选项注入您的List&lt;String&gt;,显示对话框,然后创建一个子注入器,其中包含您的选定选项列表

    然而,所有这些都是可行的,具体取决于您希望完整列表和选定列表在您的应用程序中的可访问性。

    【讨论】:

    • 感谢您的回答@Jeff Bowman!最后,我使用了Key 对象并将其绑定到一个实例(Key list = Key.get(ArrayList.class, Names.named(Constants.REQ_SERVICES));),它似乎做同样的工作。关于您对我的应用程序生命周期的评论,我的绑定或多或少是一致的:在一种情况下,我将提供一个配置文件来绑定每个服务,而另一种情况是能够在运行时将服务切换到另一个服务。我认为对于第二种情况,绑定会不太一致,这就是为什么@durron597 的答案也很有趣。
    • 啊,非常感谢 Jeff,不知道 TypeLiteral。许多其他提示推荐了类似 (new ArrayList()).getClass()) 之类的东西 - 起初我让它工作,但它似乎让 Guice 感到困惑。我无法注入实例,因为我看到了一种奇怪的行为,其中 bind(...getClass()...).toInstance(instance) 实际上会注入“new Instance()”而不是“instance”。但是,TypeLiteral 工作得很好。唷,我差点放弃这个了。
    【解决方案2】:

    我认为您误解了模块应该如何工作。

    模块不创建对象,模块定义了在需要时如何创建对象的规则。

    MapBinder 有帮助的原因是您将在单选按钮列表中定义所有服务,然后使用注入的地图来激活您需要的服务。

    这里有一些代码来说明我的意思:

    public class ServiceModule extends AbstractModule {
      protected void configure() {
        MapBinder<String, Service> mapbinder
            = MapBinder.newMapBinder(binder(), String.class, Service.class);
        mapbinder.addBinding("service1").to(Service1.class).in(Singleton.class);
        mapbinder.addBinding("service2").to(Service2.class);
        // Define ALL the services here, not just the ones being used.
        // You could also look this up from a ClassLoader or read from a configuration file if you want
      }
    }
    

    然后,将 MapBinder 注入您的 ServiceManager 类 - 这不是一个模块:

    public class ServiceManager {
      private final Map<String, Service> serviceMap;
    
      @Inject
      public ServiceManager(Map<String, Service) serviceMap) {
        this.serviceMap = serviceMap;
      }
    
      // This is just one way to do it. It depends on how your UI works
      public void startAll(List<String> serviceList) {
        for(String serviceName : serviceList) {
          serviceMap.get(serviceName).start();
        }
      }
    }
    

    【讨论】:

    • 再次感谢@durron597,您似乎对 Guice 很感兴趣;) 您的回答非常有趣,因为在这种情况下,我想根据选择激活或停用服务。您认为可以在您的服务模块中重新定义绑定吗?想象一下,对于"service1",你有Service1A.classService1B.class,MapBinder 会是一个好的解决方案吗? (当然,带有切换绑定或其他东西的功能......)
    • 还有一件事。我看到你有定义服务的模块和ServiceManager。但是您如何设法注入 serviceMap ?它不应该绑定到某个东西并通过ServiceModule 检索吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-04
    相关资源
    最近更新 更多