使用 Guice 在播放框架中注入配置值
Inject configuration value in play framework using Guice
我已经使用 conf/application.conf
玩网络应用程序(没有异常)。 Guice 用于依赖注入。 如何在class构造函数中注入属性值?代码如下。
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
。 [从我的角度来看] 完美的解决方案应该是这样的:
class FooImpl @Inject() (@Named("my.bar") override val bar: String) extends Foo {
...
}
不幸的是,这段代码不起作用,因为 Guice 没有 'my.bar' 绑定:
No implementation for java.lang.String annotated with @com.google.inject.name.Named(value=my.bar) was bound.
我想出的唯一解决方案是编写自己的模块,它遍历配置属性并将它们绑定为命名依赖项(来自 this 文档的示例的变体)。但我相信存在更好的方法。
我使用 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;
}
希望对您有所帮助。
前段时间我开发了一个小的 guice 扩展,用于映射到枚举上的简单注入配置变量
要从播放配置中注入多个属性,您可以这样做。从 Play 配置创建地图并将其作为属性传递给 Guice 活页夹。
public class Module extends AbstractModule {
private Environment environment;
private Configuration configuration;
public Module(Environment environment,Configuration configuration){
this.environment = environment;
this.configuration = configuration;
}
@Override
public void configure() {
Configuration helloConf = configuration.getConfig("myconfig");
Map<String, Object> map = helloConf.asMap();
Properties properties = new Properties();
properties.putAll(map);
Names.bindProperties(binder(), properties);
}
}
大约一年后我遇到了同样的问题,这次想出了以下解决方案(与 and 非常相似):
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 {
""
}
}
在这种情况下,应该使用 Names.named(getPrefix(entry.getValue) + path)
.
而不是 Names.named(path)
我已经使用 conf/application.conf
玩网络应用程序(没有异常)。 Guice 用于依赖注入。 如何在class构造函数中注入属性值?代码如下。
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
。 [从我的角度来看] 完美的解决方案应该是这样的:
class FooImpl @Inject() (@Named("my.bar") override val bar: String) extends Foo {
...
}
不幸的是,这段代码不起作用,因为 Guice 没有 'my.bar' 绑定:
No implementation for java.lang.String annotated with @com.google.inject.name.Named(value=my.bar) was bound.
我想出的唯一解决方案是编写自己的模块,它遍历配置属性并将它们绑定为命名依赖项(来自 this 文档的示例的变体)。但我相信存在更好的方法。
我使用 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;
}
希望对您有所帮助。
前段时间我开发了一个小的 guice 扩展,用于映射到枚举上的简单注入配置变量
要从播放配置中注入多个属性,您可以这样做。从 Play 配置创建地图并将其作为属性传递给 Guice 活页夹。
public class Module extends AbstractModule {
private Environment environment;
private Configuration configuration;
public Module(Environment environment,Configuration configuration){
this.environment = environment;
this.configuration = configuration;
}
@Override
public void configure() {
Configuration helloConf = configuration.getConfig("myconfig");
Map<String, Object> map = helloConf.asMap();
Properties properties = new Properties();
properties.putAll(map);
Names.bindProperties(binder(), properties);
}
}
大约一年后我遇到了同样的问题,这次想出了以下解决方案(与
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 {
""
}
}
在这种情况下,应该使用 Names.named(getPrefix(entry.getValue) + path)
.
Names.named(path)