使用Java管理应用程序配置属性

时间:2013-11-23 01:00:02

标签: java configuration

我正在开发一个需要一些配置文件的Java应用程序,但我总是忘记属性名称,我发现为每个配置属性创建一个get方法并不合适。但是我发现它们对我们提供的返回类型很有用。

我想知道如何在设计良好的Java应用程序中管理配置,但我想知道如果我使用这样的枚举来做它是否是一个好习惯。我想如果他们在本地化文件中会变得多么复杂。但这个想法仍然引诱着我。

public enum Confs {

    HLENGTH("hlength", Integer.class),
    ;

    private String propertyName;
    private Class type;


    private Confs(String propertyName, Class type) {
        this.propertyName = propertyName;
        this.type = type;
    }

    public Object getVal(){
// This hash map is loaded in a singleton class which uses java Properties feature to read the configuration file
        return MyLoadedConfigurationsSingleTon.getMap().get(this.propertyName);
    }

}

无论如何,是不是有解决这个问题的标准解决方案?

1 个答案:

答案 0 :(得分:3)

<强>键

这实际上取决于您的要求。这里有很多选择。对于简单的应用程序,我通常使用将任意配置键映射到值的东西。然后,可以将键的名称指定为字符串常量,例如,某处:

public static final String KEY_COLOR = "color";
public static final String KEY_SIZE = "size";

这当然会出现的问题,其中指定这些常量。您可以在某些全局共享位置指定它们(例如,在您的配置类中,或在某些特殊的常量值类中,或者甚至像您提议的那样enum)。这样做的好处是可以让您在一个地方看到所有关键名称,从而轻松避免冲突。然而,这具有明显的主要缺点,即破坏模块性并强制所有类依赖于此密钥集合 - 添加/删除/移动对象现在需要您修改全局密钥集合。

您可以做的另一件事是将配置键名称定义为实际使用它们的类/包中的字符串常量。这不会打破模块化。但是,您现在可能会将密钥名称与其他不相关的类冲突。添加新密钥意味着您必须遍历使用配置的每个对象,并确保新密钥名称尚未使用。

然而,传统的Java解决方案是让密钥名称还包括使用它们的类的包(以及可能的类名)。 E.g:

package com.me.whatever;
public class Something {
    static final String KEY_COLOR = "com.me.whatever.Something.color";
    static final String KEY_SIZE = "com.me.whatever.Something.size";
}

package com.me.util;
public class Other {
    static final String KEY_SIZE = "com.me.util.Other.size";
    static final String KEY_GROUP = "com.me.util.Other.group";
}

有时仅指定包名称更有意义,如果这更能代表您的情况。

上述想法也适用于其他配置方案。例如。使用Preferences API,可以从包名称派生密钥的路径。该API甚至提供systemNodeForPackage()之类的东西来处理这个问题。

所以,只要做任何导致最清晰,最易维护的代码。在简单性,模块化和灵活性之间找到平衡点。对于简单的丢弃应用程序来说,打破“OOP”概念并将它们全部集中在一个地方是没有错的,只要你正在做的事情是清楚的。否则,将键值存储在主要使用的位置,并利用包名和类名来确保唯一性并避免关键名称空间污染。

请注意,如果在多个包之间拆分键名,enum可能不一定是存储键名的最合适或最方便的数据类型。你当然可以想出一些聪明的系统来实现它的工作,但通常情况下,字符串常量既足够又易于使用。但是,如果您存储的不仅仅是密钥(例如值类型),enum可能是一个合适的解决方案。


价值类型

顺便说一下,对于价值类型,你也有很多选择。您可以通过客户端类进行转换,而不是在配置方面强制执行 - 但是,当然,后者在很多情况下非常方便。

使用enum的问题在于您实际上是在一个地方定义所有配置键(参见上文),并且在添加类时难以以模块化方式扩展可用的配置键集或者删除。

您可以创建一个通用配置密钥类,可以根据需要进行实例化,而不是使用固定的enum,例如:

public class Conf {

    public static class Key {

        final String key; 
        final Class<?> type;

        public Key (String key, Class<?> type) {
            this.key = key;
            this.type = type;
        }

    }

    public Object getValue (Key key) {
        ...
    }

}

通过使用泛型类型可以很容易地改进上述内容。

然后在您的客户端类中:

package com.me.whatever;
public class Something {
    static final Conf.Key KEY_COLOR = new Conf.Key("com.me.whatever.Something.color", Color.class);
    static final Conf.Key KEY_SIZE = new Conf.Key("com.me.whatever.Something.size", Integer.class);
}

再次说到关键名称:您甚至可以使包名称前缀添加为Conf.Key的函数,类似于Preferences.systemNodeForPackage()的工作原理,方法是将声明类的类型作为参数和提取包名称,以便上述声明成为,例如:

static final Conf.Key KEY_COLOR = new Conf.Key(Something.class, "color", Color.class);

<强>结论

我很喜欢,因为就像我说的那样,有无限的选择。我无法覆盖每个选项的每个案例,但希望你能得到这个想法。它更多的是以一种理智的方式接近它,而不是以一种特定的“正确”方式接近它。