在Java中从配置文件中读取配置参数的最佳方法是什么?

让我们假设直到运行时我们不知道配置的细节是什么(用户可能需要在运行应用程序之前在文件中配置这些参数。config

我想阅读这些配置详细信息,并需要在应用程序中需要的任何地方重用它们。为此,我想将它们设置为全局常量()。public static final

所以,我的疑问是,如果我直接从所需类中读取文件,是否有任何性能影响?因为,运行时值我不能直接单独放进去。configInterface

我认为这会影响性能。请建议我任何更好的方法来做到这一点。

更新:我可以使用单独的最终类来查看配置详细信息吗?将所有配置详细信息作为常量放在单独的
变量中(从配置文件中一次读取所有配置详细信息,并将其存储为全局常量以供以后在应用程序中使用)public final class


答案 1

我认为这会影响性能。

我怀疑这是否正确。

假设应用程序在启动时只读取配置文件一次,则读取该文件所花费的时间可能与应用程序的整体性能无关。实际上,应用程序运行的时间越长,启动时间就越不重要。

标准建议是,只有在有具体证据(即测量)表明性能一个重大问题时,才优化应用程序性能。然后,仅优化分析告诉您实际上是性能瓶颈的代码部分。


我可以使用单独的最终类来查看配置详细信息吗?

是的,这是可能的。没有人会阻止你1。但是,这是一个坏主意。任何意味着您需要重新编译代码以更改配置参数的事情都是一个坏主意。国际 海事 组织。


从配置文件中一次读取所有配置详细信息,并将其存储为全局常量以供以后在应用程序中使用。

啊。。。所以你实际上想要读取“常量”的值,而不是硬连线它们。

是的,这是可能的。而且它比将配置参数硬连接到代码中更有意义。但这仍然不是一个好主意(IMO)。

为什么?好吧,让我们看看代码必须是什么样子的:

public final class Config { 
    public static final int CONST_1;
    public static final String CONST_2;
   
    static {
        int c1;
        String c2;
        try (Scanner s = new Scanner(new File("config.txt"))) {
            c1 = s.nextInt();
            c2 = s.next();
        } catch (IOException ex) {
            throw RuntimeException("Cannot load config properties", ex);
        }
        CONST_1 = c1;
        CONST_2 = c2; 
    }
}

第一个观察结果是,类是 没有区别。它声明字段,因为这使它们成为常量。(将类声明为可防止子类化,但这对字段没有影响。静态字段不受继承的影响。finalfinalfinalstatic

接下来的观察是,这段代码在很多方面都很脆弱:

  • 如果静态初始值设定项块中出现问题。由块引发的未选中的异常将被包装为(是的...它是一个!!),并且该类将被标记为错误。ExceptionInInitializerErrorErrorConfig

  • 如果发生这种情况,就没有现实的恢复希望,甚至可能是一个坏主意来尝试和诊断.Error

  • 上面的代码在类初始化时执行,但确定何时发生这种情况可能很棘手。Config

  • 如果配置文件名是参数,那么您就存在掌握参数值的问题...在触发静态初始化之前。

接下来,与将状态加载到实例变量中相比,代码非常混乱。这种混乱很大程度上是由于必须在静态初始值设定项的约束下工作的结果。下面是改用实例变量时代码的外观。final

public final class Config { 
    public final int CONST_1;
    public final String CONST_2;
   
    public Config(File file) throws IOException {
        try (Scanner s = new Scanner(file)) {
            CONST_1 = s.nextInt();
            CONST_2 = s.next();
        } 
    }
}

最后,字段相对于字段的性能优势很小:static finalfinal

  • 可能每次访问其中一个常量时都会有一两条机器指令,

  • 如果 JIT 编译器是智能的,并且您适当地处理单例引用,则可能根本没有任何内容。Config

在任何一种情况下,在绝大多数情况下,好处都是微不足道的。


1 - 确定...如果你的代码是代码审查的,那么有人可能会阻止你。


答案 2

你有没有听说过apache commons configuration http://commons.apache.org/proper/commons-configuration/?它是我找到的最好的配置读取器,甚至在我的应用程序中使用它,该应用程序自1年以来一直在生产中运行。从未发现任何问题,非常容易理解和使用,性能极佳。我知道这有点依赖于您的应用程序,但相信我,您会喜欢它。

您需要做的就是

Configuration config = new ConfigSelector().getPropertiesConfiguration(configFilePath);
String value = config.getString("key");
int value1 = config.getInt("key1");
String[] value2 = config.getStringArray("key2");
List<Object> value3 = config.getList("key3");

就是这样。您的配置对象将保存所有配置值,您可以根据需要将该对象传递给任意数量的类。有这么多可用的有用方法,您可以提取所需的任何类型的密钥。