首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >使用Guice在play框架中注入配置值

使用Guice在play框架中注入配置值
EN

Stack Overflow用户
提问于 2016-05-24 14:32:29
回答 4查看 3.5K关注 0票数 1

我用conf/application.conf玩网络应用程序(没什么不寻常的)。Guice用于依赖注入。如何在类构造函数中注入属性值?代码如下。

代码语言:javascript
代码运行次数:0
运行
复制
class MyController @Inject() (private val foo: Foo) extends Controller {
    ...
}

@ImplementedBy(classOf[FooImpl])
trait Foo { 
    def bar: String
}

class FooImpl extends Foo {
    override val bar = current.configuration.getString("my.bar").get
    ...
}

在当前的配置中,如果不运行应用程序,就无法测试FooImpl。我希望能够在单元测试中实例化FooImpl。在我看来,完美的解决方案应该是这样的:

代码语言:javascript
代码运行次数:0
运行
复制
class FooImpl @Inject() (@Named("my.bar") override val bar: String) extends Foo {
    ...
}

不幸的是,这段代码无法工作,因为Guice没有“my.bar”绑定:

没有绑定带@com.google.inject.name.Named注释的@com.google.inject.name.Named(value=my.bar)的实现。

我想出的唯一解决方案是编写自己的模块,它迭代配置属性并将它们绑定为命名依赖项(来自文档的示例的一个变体)。但我相信有一种更好的办法。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2017-07-25 06:06:06

大约一年后,我遇到了同样的问题,这次我想出了以下解决方案(非常类似于由“陌生人”提出的建议@droidman):

代码语言:javascript
代码运行次数:0
运行
复制
class InjectionModule extends AbstractModule {

  override def configure(): Unit = {

    val config: Config = TypesafeConfigReader.config
    config.entrySet().asScala.foreach { entry =>
      val path = entry.getKey
      entry.getValue.valueType() match {
        case ConfigValueType.NUMBER =>
          bind(classOf[Int])
            .annotatedWith(Names.named(path))
            .toInstance(config.getInt(path))
        case ConfigValueType.BOOLEAN =>
           bind(classOf[Boolean])
             .annotatedWith(Names.named(path))
             .toInstance(config.getBoolean(path))
        case ConfigValueType.STRING =>
           bind(classOf[String])
             .annotatedWith(Names.named(path))
             .toInstance(config.getString(path))
        case _ =>
      }
    }
  }
}

此外,还可以通过在系统属性中添加前缀(键-值对是加载配置的一部分)来扩展此方法:

代码语言:javascript
代码运行次数:0
运行
复制
private def getPrefix(configValue: ConfigValue): String = {
  val description = configValue.origin().description()
  if (description.contains("system properties")) {
    "sys."
  } else {
    ""
  }
}

在这种情况下,人们应该使用Names.named(path),而不是编写Names.named(getPrefix(entry.getValue) + path)

票数 1
EN

Stack Overflow用户

发布于 2016-05-24 15:46:57

我使用Java实现了这个功能。我希望您可以将它用作Scala实现的参考。

首先,我创建了一个模块:

代码语言:javascript
代码运行次数:0
运行
复制
public class MainModule extends AbstractModule {
    public final static String TIMEOUT_IN_MILLISECONDS_ANNOTATION = "timeout-promise";
    private final Configuration configuration;

    public MainModule(@SuppressWarnings("unused") Environment environment, Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    protected void configure() {
        long timeoutInMilliseconds = configuration.getLong("application.promise.timeout.in.milliseconds", 0L);
        bindConstant().annotatedWith(Names.named(TIMEOUT_IN_MILLISECONDS_ANNOTATION)).to(timeoutInMilliseconds);
    }
}

之后,我只在不同的地方使用了注释:

代码语言:javascript
代码运行次数:0
运行
复制
class Service {

    @Inject
    @Named(MainModule.TIMEOUT_IN_MILLISECONDS_ANNOTATION)
    protected long timeoutInMilliseconds;

}

希望这能有所帮助。

票数 2
EN

Stack Overflow用户

发布于 2016-05-25 15:45:59

不久前,我开发了用于映射到Enum上的简单注入配置变量的小guice扩展程序。

guice-config

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37416614

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档