Dagger:注入@Named字符串?

问题描述 投票:0回答:2

编辑 2023-06-28:除非你有充分的理由不这样做,否则只需使用 Spring Boot 作为你的平台,并使用它的自动布线以及所有其他免费的好东西。

编辑 2018-02-08:演示如何执行此操作的示例项目,位于 https://github.com/ravn/dagger2-named-string-inject-example - 注意:整个源代码位于单个文件


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

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

例如如果我有

java.util.Map<String, String> map = new java.util.TreeMap<String, String>();
map.put("key", "value");

@Inject
Thermosiphon(Heater heater, @Named("key") String value) {
    this.heater = heater;
    System.out.println("value =" + 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)

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

dependency-injection dagger
2个回答
24
投票

听起来你有一个 Map 并且你想使用一些东西来将它们自动绑定到命名字符串。您无法像在 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("stringliteral") 。哎呀,如果你已经将属性名称和默认值定义为常量字符串,你甚至可以做:

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

它是更多的样板文件,但 Dagger 在尝试消除大量样板文件的同时,更喜欢编译时分析而不是绝对减少样板文件。也就是说,我将提出一个可以改善这种情况的功能,从已知列表或类似的列表中自动生成系统属性的模块。我认为即使是这个样板也可以减少。


23
投票

您必须在 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);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.