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

Sag*_*udi 20 java oop configuration runtime initialization

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

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

所以,我怀疑的是,如果我config直接从所需的类中读取文件,是否有任何性能影响?既然,运行时值我不能直接放在一起Interface.

我认为它会影响性能.请建议我做任何更好的方法.

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

Ste*_*n C 21

我认为它会影响性能.

我怀疑这是真的.

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

当您有具体证据(即测量)表明性能一个重要问题时,标准建议是仅优化应用程序性能.然后,只优化代码中那些分析告诉您确实是性能瓶颈的部分.


我可以使用单独的final类来获取配置详细信息

是的,有可能做到这一点.没有人会阻止你1.但是,这是一个坏主意.任何意味着您需要重新编译代码以更改配置参数的事情都是一个坏主意.IMO.


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

啊......所以想要读取"常量"的值而不是硬连线.

是的,这是可能的.并且它比将配置参数硬连接到代码中更有意义.但它仍然不是一个好主意(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; 
    }
}
Run Code Online (Sandbox Code Playgroud)

首先观察的是,这个类没有区别final.据宣布领域final,使他们不断.(将类声明为final阻止子类化,但这对static字段没有影响.静态字段不受继承影响.)

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

  • 如果静态初始化程序块出现问题.块抛出的未经检查的异常将被包装为ExceptionInInitializerError(是的......它是Error!!),并且Config该类将被标记为错误.

  • 如果发生这种情况,就没有恢复的现实希望,尝试和诊断它可能是一个坏主意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();
        } 
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,static final字段对final字段的性能优势很小:

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

  • 如果JIT编译器是智能的,你可能没有任何东西,你可以Config适当地处理单例引用.

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


1 - 好的......如果你的代码经过代码审查,那么有人可能会阻止你.


Sri*_*777 20

您是否听说过apache commons配置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");
Run Code Online (Sandbox Code Playgroud)

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


San*_*mar 5

如果将它们放在属性文件中并在应用程序的开头读取文件并将所有参数初始化为系统参数(System.setProperty),然后在代码中定义常量,则只需要一次性成本

public static final String MY_CONST = System.getProperty("my.const");
Run Code Online (Sandbox Code Playgroud)

但是在加载任何其他类之前,请确保在应用程序启动时进行初始化.


Adr*_*ter 5

有不同类型的配置.

通常需要某种引导配置(例如连接到数据库或服务)才能启动应用程序.指定数据库连接参数的J2EE方法是通过容器的JNDI注册表(Glassfish,JBoss,Websphere,...)中指定的"数据源".然后在persistence.xml中按名称查找此数据源.在非J2EE应用程序中,更常见的是在Spring上下文或甚至.properties文件中指定它们.在任何情况下,您通常都需要一些东西来将您的应用程序连接到某种数据存储.

引导到数据存储后,选项是管理此数据存储区中的配置值.例如,如果您有数据库,则可以使用单独的表(在应用程序中由JPA实体表示)来获取配置值.如果您不想/需要这种灵活性,可以使用简单的.properties文件.Java(ResourceBundle)和Spring等框架中的.properties文件都有很好的支持.vanilla ResourceBundle只加载属性一次,Spring助手提供可配置的缓存和重新加载(这有助于你提到的性能方面).注意:您还可以使用由数据存储而不是文件支持的属性.

通常,两种方法在应用程序中共存.可以从属性文件中读取在已部署的应用程序中永不更改的值(如应用程序名称).应用程序维护者在运行时可能需要更改的值而不进行重新部署(例如会话超时间隔)可能更好地保存在可重新加载的.properties文件或数据库中.应用程序用户可以更改的值应保存在应用程序的数据存储中,并且通常具有应用程序内屏幕以进行编辑.

所以我的建议是将配置设置分为几类(例如,引导程序,部署,运行时和应用程序),并选择适当的机制来管理它们.这还取决于您的应用程序的范围,即它是J2EE Web应用程序,桌面应用程序,命令行实用程序,批处理过程?