当前位置: 首页 > 知识库问答 >
问题:

使用 Guice 在游戏框架中注入配置值

米项禹
2023-03-14

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

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
    ...
}

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

class FooImpl @Inject() (@Named("my.bar") override val bar: String) extends Foo {
    ...
}

不幸的是,这段代码不起作用,因为Guice没有“my”。bar绑定:

没有绑定使用 @com.google.inject.name.Named(value=my.bar) 注释的 java.lang.String 的实现。

我想出的唯一解决方案是编写我自己的模块,该模块遍历配置属性并将它们绑定为命名依赖项(本文档中示例的变体)。但我相信存在更好的方法。

共有3个答案

韦衡
2023-03-14

大约一年后,我遇到了同样的问题,这次我提出了以下解决方案(与@ q中的陌生人和@droidman提出的方案非常相似):

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 _ =>
      }
    }
  }
}

此外,可以通过将前缀附加到系统属性(哪些键值对是加载的配置的一部分)来扩展此方法

private def getPrefix(configValue: ConfigValue): String = {
  val description = configValue.origin().description()
  if (description.contains("system properties")) {
    "sys."
  } else {
    ""
  }
}

在这种情况下,不要编写<code>Names。named(path)应该使用Names.named(getPrefix(entry.getValue)path)

司徒嘉祥
2023-03-14

前段时间我开发了小guice扩展,用于在Enum上映射的简单注入配置变量

guice-config

洪俊拔
2023-03-14

我用Java实现了它。我希望您可以将它作为Scala实现的参考。

起初,我创建了一个模块:

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);
    }
}

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

class Service {

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

}

希望这有帮助。

 类似资料:
  • 在Play 2.2中,我创建了GlobalActor制作类 我想将游戏框架升级到 2.5。Play.current在play 2.5中被弃用,所以我使用注入器修改了这个类,但注入器始终为Null。我需要如何使这门课在 Play 2.5 中工作?

  • 我有 对于这个特性,我有多个实现。。。 根据给定的类型,我想从一个实现中选择。类似这样的东西(伪代码): 所以2点: > 如何注入trait“Builder”的所有实现??我发现了很多问题都是朝着同一个方向发展的(使用multibinder、TypeLiteral等,但没有一个问题涉及注入所有实现。这只是关于“如何注入特定的实现”),我知道如何使用multibinder绑定多个实例;但如果它是一个

  • 我正在使用Guice和Dropwizard开发一个应用程序,在其中我们创建了不同的包,如Guice包、migrations包等,并将它们添加到initialize()方法中的bootstrap中。 注意:我知道另一种方法,您可以在run()方法中创建Module类的对象,用于创建注入器(配置和环境对象在MyModule类的构造函数中作为参数传递)。但这需要我在run()方法中注册所有托管对象和所有

  • nebula3 是一个游戏引擎和开发框架,可移植的特性支持多平台,包括 iPhone。 http://code.google.com/p/nebula3-engine/

  • 我正在努力实现DI,特别是使用guice的构造函数注入。我很难理解如何将泛型的类类型注入到构造函数中。 我的课程如下: 我可以在运行时使用guice将类的类型注入构造函数吗?简而言之,我可以使用guice注入Foo构造函数吗?

  • 本项目是win32下大型客户端游戏的游戏辅助开发框架,由于它集成并包含了游戏辅助开发的各方面功能,称本项目为win32辅助开发的组件也可。 内含具体项目有fifa online3、疾风之刃、怪物猎人online、流放之路等,也有辅助帐号验证服务器,帐号查寻与管理工具,特征码识别,资源文件系统等。 本人现已转型,特发布此项目,旨在分享一份只供参考的多年工作经验与心血,若本项目中有些您认为闪亮的设计、