Dependency injection 匕首:注入@命名字符串?

Dependency injection 匕首:注入@命名字符串?,dependency-injection,dagger,Dependency Injection,Dagger,编辑2018-02-08:示范如何在以下位置执行此操作的示例项目-注: 我正在研究dagger是否可以为我们取代guice(因为我们的Java平台部署缓慢) 我在运行时构造了一个配置字符串的映射,我希望根据需要进行dagger注入 如果我有 java.util.Map<String, String> map = new java.util.TreeMap<String, String>(); map.put("key", "value"); 我希望在价值中注入“价值”

编辑2018-02-08:示范如何在以下位置执行此操作的示例项目-注:


我正在研究dagger是否可以为我们取代guice(因为我们的Java平台部署缓慢)

我在运行时构造了一个配置字符串的映射,我希望根据需要进行dagger注入

如果我有

java.util.Map<String, String> map = new java.util.TreeMap<String, String>();
map.put("key", "value");
我希望在价值中注入“价值”

源代码中的示例没有任何@Named用法。仅尝试会出现以下异常:

Exception in thread "main" java.lang.IllegalStateException: Errors creating object graph:
  No binding for @javax.inject.Named(value=key)/java.lang.String required by class bar.Thermosiphon
    at dagger.internal.ThrowingErrorHandler.handleErrors(ThrowingErrorHandler.java:34)
    at dagger.internal.Linker.linkRequested(Linker.java:146)
    at dagger.ObjectGraph$DaggerObjectGraph.getInjectableTypeBinding(ObjectGraph.java:288)
    at dagger.ObjectGraph$DaggerObjectGraph.get(ObjectGraph.java:249)
    at app.CoffeeApp.main(CoffeeApp.java:20)

我应该如何处理这个问题?

您必须在dagger模块中为@Named实例定义一个提供程序

@Provides @Named("foo") String provideFoo()
{
    return "foo string";
}
然后可以在构造函数中注入命名实例,或者在依赖类中使用字段注入

public class Thermosiphon
{
    @Inject @Named("foo") String fooString;

    @Inject public Thermosiphon(Heater heater)
    {
        System.out.println("value of fooString is " + fooString);
    }
}

听起来好像你有一个映射,你想用一些东西将这些自动绑定到命名字符串。您不能像在Guice中那样在Dagger中自动执行此操作,因为在Guice中可以创建属性绑定器

Dagger需要在编译时了解所有绑定,以便进行分析以确保满足所有绑定和依赖项

这就是说,你可以这样做-这是更多的锅炉板,但它是合法的

@Module(library = true)
public class PropertiesModule {
  public final Properties props;

  PropertiesModule(Properties props) {
    this.props = props;
  }

  @Provides @Named("property.one") String providePropertyOne() {
    props.getProperty("property.one", "some default");
  }

  @Provides @Named("property.two") String providePropertyTwo() {
    props.getProperty("property.two", "some other default");
  }
  ...
}
这将允许创建所有需要创建的绑定,但要从运行时值中得到满足。但是,这些键在编译时是已知的(而且必须是已知的,因为您在代码中使用了@Named(“string literal”)。见鬼,如果您将属性名和默认值定义为常量字符串,您甚至可以执行以下操作:

  @Provides @Named(PROPERTY_NAME_CONSTANT) String a() {
    props.getProperty(PROPERTY_NAME_CONSTANT, PROPERTY_NAME_CONSTANT_DEFAULT);
  }

它更多的是锅炉板,但Dagger在试图消除大量锅炉板的同时,更倾向于编译时分析,而不是绝对锅炉板缩减。也就是说,我将提出一个特性来改善这种情况,从已知列表或类似列表中自动生成系统属性的模块。我认为即使是这个锅炉板也可以重新生成duced.

我的字符串是在运行时读取的属性文件中设置的,可能包含任意值。我是否需要为每个可能的键提供一个提供程序?目前,没有在运行时创建新的任意绑定的方法,因为Guice中存在这种方法-这将违反Dagger严格的编译时分析要求。您必须知道对象图的因此,您必须提前拥有所有这些命名绑定。尽管这最初看起来像是更多的工作,但我认为它可以提供模块化应用程序(尤其是我们的用例)经常需要支持的属性的集中文档。我将尝试一下。指定一个在源代码中列出这些属性,并由注释处理器生成getter。我不需要默认值-如果错误消息中没有键,我需要运行时异常。是的,我认为我们需要一个代码生成解决方案-从属性列表生成模块。我现在已经完成了一些原型设计和每个键所需的额外工作都比在方法体中指定确切行为的能力和放置javadoc的中心位置付出的更多。换句话说,您的建议比我自己的建议更好地解决了我的实际问题。谢谢。这是否曾导致dagger中出现特性[请求]?
  @Provides @Named(PROPERTY_NAME_CONSTANT) String a() {
    props.getProperty(PROPERTY_NAME_CONSTANT, PROPERTY_NAME_CONSTANT_DEFAULT);
  }