我想在 java webapp 中创建一个适当的属性管理策略,将 google guice 作为 DI 框架进行中继。
我想要一种机制来满足以下 3 个要求:
我相信这是标准要求。现在,使用 guice 标准 Binder ,我可以轻松获得第一个要求,但不能获得其他两个要求。为了获得另外两个,我创建了自己的类来执行以下操作:
public static void bindString(AnnotatedBindingBuilder<String> binder, String property, String defaultValue) {
binder.annotatedWith(Names.named(property)).toInstance(getProperty(property, defaultValue));
}
getProperty 方法知道如何处理我的属性(从 war 或系统级别获取值)并静态公开属性。
所以基本上,只要我使用我为属性绑定(bind)创建的这个实用程序,我就很好,它涵盖了我的所有要求,但一旦我使用标准 guice 绑定(bind),我就失去了第二个和第三个要求。
有没有办法覆盖 guice 绑定(bind)并获得所有这 3 个要求?
有一次我在一个基于 spring 的应用程序中遇到了同样的挑战并且非常简单。我使用以下方法实现了 ApplicationContextInitializer:
@Override
public void initialize(ConfigurableWebApplicationContext ctx) {
PropertySource<Map<String, Object>> localProps = null;
try {
localProps = new ResourcePropertySource(new ClassPathResource(LOCAL_PROPERTIES_FILE_NAME));
} catch (IOException e) {
LOG.fatal("Could not load local properties from classpath " + LOCAL_PROPERTIES_FILE_NAME);
return;
}
LOG.info("Loaded configuration from classpath local file " + LOCAL_PROPERTIES_FILE_NAME);
ctx.getEnvironment().getPropertySources().addFirst(localProps);
}
所以这为我提供了一种方法,可以将具有最高优先级的本地属性添加到我的环境中。在与 war 属性(property)重叠的情况下,本地属性(property)具有更高的优先级。此外,我静态地公开了我的环境,因此我可以静态访问我的属性(对于不由容器管理的服务,主要是遗留服务)。
如何使用 guice 实现此目的?
最佳答案
不幸的是,我不认为您会找到任何可以为您提供真正干净和令人满意的实现的东西。尤其是,我不认为如果您不自己至少实现其中的一部分,您将找不到任何能够准确满足您需求的东西。
如果我有这些需求,我会确保我的注入(inject)器是在中央 InjectorFactory 中创建的。如果你需要大量来自外部的参数来创建你的注入(inject)器,我会在我的应用程序的最开始简单地创建一次,然后将注入(inject)器缓存到一个静态的最终字段中。这将使它可用于静态方法。我会将我的“回退”属性加载绑定(bind)到一个显式提供程序。这样,我将不使用标准的 Names.bindProperties(...) 方法,而是将其直接绑定(bind)到 Provider。然后,该提供程序实现执行回退或合并多个属性文件所必需的逻辑。将注入(inject)器缓存到静态字段意味着我可以调用静态方法来访问注入(inject)类之外的全局上下文中的属性。
使用您自己的供应商最初似乎令人不快,但可以提供一些额外的好处。对于初学者,您可以完全按照自己的意愿实现回退策略。此外,您可以添加其他行为,例如自动重新加载您的属性文件等(我的代码示例中未显示)。
public class InjectorFactory {
private static Injector injector = null;
public static synchronized Injector getOrCreateInjector() {
if(injector == null) {
injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
Properties properties1 = createProperties("file1.properties");
Properties properties2 = createProperties("file2.properties");
Set<Object> propertyNames = new HashSet<Object>();
propertyNames.addAll(properties1.keySet());
propertyNames.addAll(properties2.keySet());
for (Object object : propertyNames) {
String propertyName = (String) object;
bind(String.class).annotatedWith(Names.named(propertyName)).toProvider(new StringProvider(properties1, properties2, propertyName));
}
}
private Properties createProperties(String propertyFileName) {
try {
InputStream stream = InjectorFactory.class.getResourceAsStream(propertyFileName);
try {
Properties properties = new Properties();
properties.load(stream);
return properties;
} finally {
stream.close();
}
} catch (IOException exception) {
throw new RuntimeException("Could not load properties file");
}
}
});
}
return injector;
}
public static String getProperty(String propertyName) {
return getOrCreateInjector().getInstance(Key.get(String.class, Names.named(propertyName)));
}
}
给定上述代码和 file1.properties:
property1=Property1Value
property2=Property2Value
和文件.properties:
property2=IncorrectProperty2Value
property3=Property3Value
与供应商
public class StringProvider implements Provider<String> {
private Properties properties1;
private Properties properties2;
private String propertyName;
public StringProvider(Properties properties1, Properties properties2,
String propertyName) {
this.properties1 = properties1;
this.properties2 = properties2;
this.propertyName = propertyName;
}
public String get() {
if(properties1.containsKey(propertyName)) {
return properties1.getProperty(propertyName);
}
return properties2.getProperty(propertyName);
}
}
以下用法:
public class InjectorFactoryTest {
public static void main(String ... parameters) {
System.out.println(InjectorFactory.getProperty("property1"));
System.out.println(InjectorFactory.getProperty("property2"));
System.out.println(InjectorFactory.getProperty("property3"));
}
}
输出:
Property1Value
Property2Value
Property3Value
关于java - Google Guice 属性管理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33496948/
我正在使用i18n从头开始构建一个多语言网络应用程序,虽然我自己可以处理一大堆yml文件,但我说的语言(非常)有限,最终我想寻求外部帮助帮助。我想知道这里是否有人在使用UI插件/gem(与django上的django-rosetta不同)来处理多个翻译器,其中一些翻译器不愿意或无法处理存储库中的100多个文件,处理语言数据。谢谢&问候,安德拉斯(如果您已经在rubyonrails-talk上遇到了这个问题,我们深表歉意) 最佳答案 有一个rails3branchofthetolkgem在github上。您可以通过在Gemfi
我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog
对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs
我安装了ruby版本管理器,并将RVM安装的ruby实现设置为默认值,这样'哪个ruby'显示'~/.rvm/ruby-1.8.6-p383/bin/ruby'但是当我在emacs中打开inf-ruby缓冲区时,它使用安装在/usr/bin中的ruby。有没有办法让emacs像shell一样尊重ruby的路径?谢谢! 最佳答案 我创建了一个emacs扩展来将rvm集成到emacs中。如果您有兴趣,可以在这里获取:http://github.com/senny/rvm.el
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我