如何使用rocoto实现覆盖属性策略?

时间:2012-03-06 09:51:10

标签: java properties guice

我想在我的应用程序中实现属性策略:我想在我的应用程序中定义默认属性,并且在我的情况下,我希望保留通过war文件之外的配置文件覆盖此默认参数的可能性。

所以我定义了一个ConfigModule.java:

public class ConfigModule extends AbstractModule {

    private static final Logger LOG = LoggerFactory.getLogger(BatchConfigModule.class);

    @Override
    protected void configure() {

        LOG.info("Start rocoto configuration");
        Module rocotoModule = Rocoto.expandVariables(new ConfigurationModule() {
            @Override
            protected void bindConfigurations() {
                // default config
                LOG.debug("Default config");
                bindProperties(Config.DEFAULT_CONFIG);
                LOG.debug("before config.properties");
                // // For overriding default config
                File propertiesFile = new File(Resources.getResource("config.properties")
                        .getFile());
                if (propertiesFile.exists()) {
                    LOG.info("config.properties was found in classpath: ["
                            + propertiesFile.getAbsolutePath() + "]");
                    bindProperties(propertiesFile);
                } else {
                    LOG.info("config.properties was not found in classpath");
                }
            }
        });
        install(rocotoModule);

    }
}

Config.DEFAULT_CONFIG扩展了java.util.Properties并定义了默认属性,DEFAULT_CONFIG中的每个参数都是这样的=>

DEFAULT_CONFIG.setProperty("testModeInt", "${testMode|false}");

我用@Named(“testModeInt”)注入我的代码属性。

我的问题是,如果我的config.properties在classpath中不存在,我有一个错误:

Caused by: java.lang.IllegalStateException: Re-entry not allowed
    at com.google.inject.internal.util.$Preconditions.checkState(Preconditions.java:142)
    at org.nnsoft.guice.rocoto.configuration.ConfigurationModule.configure(ConfigurationModule.java:63)
    at com.google.inject.AbstractModule.configure(AbstractModule.java:59)
    at com.google.inject.spi.Elements$RecordingBinder.install(Elements.java:223)
    at com.google.inject.spi.Elements.getElements(Elements.java:101)
    at com.google.inject.spi.Elements.getElements(Elements.java:92)
    at com.google.inject.util.Modules$RealOverriddenModuleBuilder$1.configure(Modules.java:152)
    at com.google.inject.AbstractModule.configure(AbstractModule.java:59)
    at com.google.inject.spi.Elements$RecordingBinder.install(Elements.java:223)
    at com.google.inject.AbstractModule.install(AbstractModule.java:118)
    at net.antoine.ConfigModule.configure(ConfigModule.java:51)

我只是不明白,这个问题来自哪里,或者这个实现可能不好,另一个想法?

1 个答案:

答案 0 :(得分:0)

您可以尝试OWNER API:它支持3级属性覆盖,它还提供Java对象和属性文件以及其他简洁功能之间的映射。

第一个覆盖功能是在映射接口上指定默认值:

public interface ServerConfig extends Config {
    @DefaultValue("42")
    int maxThreads();
}

ServerConfig默认映射到同一个包中的ServerConfig.properties。如果未指定属性“maxThreads”,则默认使用42(属性文件将覆盖DefaultValue)。

第二个覆盖功能是可以为类指定多个属性文件位置,因此使用找到的第一个资源。这样,您可以在jar中定义内部属性,并允许用户在其主目录或/ etc / myapp中或您喜欢的任何其他位置指定覆盖属性文件:

@Sources({ "file:~/.myapp.config", 
           "file:/etc/myapp.config", 
           "classpath:foo/bar/baz.properties" })
public interface ServerConfig extends Config {

    @Key("server.http.port")
    int port();

    @Key("server.host.name")
    String hostname();

    @Key("server.max.threads");
    @DefaultValue("42")
    int maxThreads();
}

第三个覆盖功能是指定您想要考虑所有上述文件,但是您希望覆盖发生在属性级别,以便如果以上所有 属性文件可用,当您要求属性maxThreads()时,将首先在file:~/.myapp.config中搜索 - 如果未找到 - 则在file:/etc/myapp.config然后在classpath:foo/bar/baz.properties中搜索,作为最后的手段,@DefaultValue("42")适用,然后您指定库必须生成所有属性资源的合并(并将其全部考虑)

@LoadPolicy(LoadType.MERGE)
@Sources({ "file:~/.myapp.config", 
           "file:/etc/myapp.config", 
           "classpath:foo/bar/baz.properties" })
public interface ServerConfig extends Config {
    // same content as above.
}