草庐IT

java - Google Guice 属性管理

coder 2024-03-21 原文

我想在 java webapp 中创建一个适当的属性管理策略,将 google guice 作为 DI 框架进行中继。

我想要一种机制来满足以下 3 个要求:

  • 我希望能够使用 guice (@Named) 注入(inject)属性
  • 我希望能够以静态方式访问属性
  • 该机制应该支持属性的优先级排序,这意味着一个属性可以用一定的值包装在已部署的 war 中,但它也可以在目标系统级别或本地文件系统(我部署的目标机器的)中是冗余的,在这种情况下,war 中的值将被目标机器中存在的值覆盖。

我相信这是标准要求。现在,使用 guice 标准 Binder ,我可以轻松获得第一个要求,但不能获得其他两个要求。为了获得另外两个,我创建了自己的类来执行以下操作:

  • 包装并公开 guice 的绑定(bind)方法(绑定(bind)属性的方法)例如:

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/

有关java - Google Guice 属性管理的更多相关文章

  1. ruby - i18n Assets 管理/翻译 UI - 2

    我正在使用i18n从头开始​​构建一个多语言网络应用程序,虽然我自己可以处理一大堆yml文件,但我说的语言(非常)有限,最终我想寻求外部帮助帮助。我想知道这里是否有人在使用UI插件/gem(与django上的django-rosetta不同)来处理多个翻译器,其中一些翻译器不愿意或无法处理存储库中的100多个文件,处理语言数据。谢谢&问候,安德拉斯(如果您已经在ruby​​onrails-talk上遇到了这个问题,我们深表歉意) 最佳答案 有一个rails3branchofthetolkgem在github上。您可以通过在Gemfi

  2. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的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

  3. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  4. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型: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

  5. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  6. ruby - Nokogiri 剥离所有属性 - 2

    我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

  7. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

    对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

  8. ruby-on-rails - 获取 inf-ruby 以使用 ruby​​ 版本管理器 (rvm) - 2

    我安装了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

  9. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用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

  10. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

随机推荐