[英]Injecting a List of Strings From a Properties File Using Guice
我有一个应用程序需要从 Properties 文件中读取一些配置值,然后使用 Guice 的 @Named 注释注入这些值。 我目前正在我的模块中做这样的事情:
@Override
protected void configure() {
try {
Properties properties = getProperties();
Names.bindProperties(binder(), properties);
binder().bind(MyApi.class);
} catch (Exception e) {
log.error(e.getMessage());
throw new RuntimeException(e);
}
}
然后在我的应用程序中我做了类似的事情:
public class MyApi
{
@Inject
@Named("ftp.dir")
public String ftpDirectory;
}
这种方法适用于注入原始值,但现在我需要注入一个字符串列表。 如果我只是添加注射
@Inject
@Named("mail.to")
public List<String> mailTo;
对于像这样的属性文件:
#Properties
ftp.dir=/opt/my/dir
mail.to=foo@bar.com, abc@123.com
然后 guice 会抛出一个异常说
'未绑定带有 @google.inject.name.Named(value=mail.to) 注释的 java.util.List<java.lang.String> 的实现'。
我见过一些其他类似的问题,例如: Guice: Inject an ArrayList of Strings和 Injecting list of strings in Guice但所有解决方案都采用为字段添加显式绑定的方法。
有什么方法可以在 guice 中处理 collections 而不必从属性文件中手动提取它们并添加显式绑定?
我设法找到了满足我需求的解决方案。 Guice 3.0 有一种通过 Binder.convertToTypes() 方法添加自定义类型转换器的方法。 我简单地调用了这个方法并传入了 com.google.inject.spi.TypeConverter 的实现,它会获取属性值并将其从字符串转换为列表。 我模块中的配置方法最终看起来像这样:
@Override
protected void configure() {
try {
//I'm using apache commons-configurations here but you could
//just as easily use just a java Properties object
Configuration properties = getProperties();
//I'm using the builtin Matchers.only from guice for this simple
//case but you could implement a custom Matcher for more complex
//behavior
binder().convertToTypes(Matchers.only(new TypeLiteral<List<String>>(){}),
new TypeConverter() {
//again, I'm using commons-configuration to perform the
//actual conversion but you could use a different library
//or even do the conversion yourself if needed
final DefaultListDelimiterHandler handler = new DefaultListDelimiterHandler(',');
@Override
public Collection<String> convert(String value, TypeLiteral<?> toType) {
return handler.split(value, true);
}
});
//now that guice has a converter registered for List<String>
//we can simply use bindProperties to set up the Named bindings
Names.bindProperties(binder(), ConfigurationConverter.getProperties( properties));
binder().bind(MyApi.class);
} catch (Exception e) {
log.error(e.getMessage());
throw new RuntimeException(e);
}
}
此解决方案的优势在于它减少了 my.properties 文件与实际代码之间的耦合。 如果我想用 List 值添加额外的属性,我可以简单地更改属性文件,而无需为每个新属性添加自定义提供程序方法。 我的代码和属性文件之间的唯一耦合是在 @Named 注释中。
可能有更好的解决方案; 如果你有什么事请告诉我。 如果要将此问题再开放几天,以防万一有人有更好的建议。
如果将此方法添加到模块中会怎样?
@Named("mail.to") List<String> provideMailtoAsList(@Named("mail.to") String mailto) {
return List.of(mailto.trim().split("\\s*,\\s*"));
}
这会将名为“mail.to”的已知String
转换为恰好也名为“mail.to”的List<String>
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.