什么是加载属性的最佳策略?

12

我有几个类需要加载一些属性文件,我想知道实现这一点的最佳做法是什么。我想到了两种基本方法:

  • 在每个类中硬编码属性文件的名称,然后使用Properties类从FileInputStream中加载,如果有人决定更改属性文件的名称,那么它将被硬编码在代码中,可能会引起问题。

  • public class A {
        public A() {
            Properties p = new Properties().load(
                    new FileInputStream("properties/Aconfig.properties"));
            String value = p.getProperty("key", "");
        }        
    }
    
    创建一个方法,给定一个类名,它可以加载与该类同名的属性文件。虽然这种方法不需要硬编码属性文件名,但需要按照某些约定命名文件,可能会导致混淆。
    public class A {
        public A() {
            Properties p = PropertiesHelper.loadFromClassName(A.class.getName());
            // here, we **assume** that there is a A.properties file in the classpath.
        }
    }
    
    然而,可能存在许多其他更优雅的方法,这就是我提出这些问题的原因:i)在Java中加载属性文件的最佳实践是什么?ii)您是否使用任何帮助类来处理此工作?iii)通常在代码的哪个位置加载属性文件?
    此外,一个类是否可以“自动加载”其属性?还是应该将我需要的参数传递给构造函数?传递参数的问题在于某些类有太多参数(~20个,表示统计模型中的参数)。
5个回答

7

最佳实践是使用某种依赖注入容器,例如Spring FrameworkGoogle Guice

它解决了各种问题-您不会将类绑定到特定的属性文件名称,您不必担心在该类中加载所述属性并处理可能的异常,并且您不必将30个属性文件名称作为命令行参数(或系统属性)传递。

除了属性加载之外,它还有助于许多其他事情:-尝试一下,您会惊讶地发现没有它,您如何生活。

更新:顺便说一句,您的其他问题也是Spring会处理的其中之一。

更新 #2: 我刚意识到我已经试图向您推荐Spring :-) 冒着重复自己的风险,Spring在这里确实会帮助抽象化。根据您在属性文件中存储的内容,您可能根本不需要它们(如果它们处理配置),或者您将获得一个非常好的API来处理它们(如果它们是资源包或类似的东西)。

是的 : ),我正在考虑在这个特定问题上使用SF。但是,为此,我希望每个人(不一定是计算机程序员)都可以轻松配置/更改属性文件,因此需要一个简单的“键=值”文件模式。 - João Silva
你仍然可以完全做到这一点。Spring有一个非常好的资源抽象层:http://static.springsource.org/spring/docs/2.5.x/reference/resources.html,它可以让您直接处理这些属性文件,而不必直接将您的类与它们绑定。 - ChssPly76
嗯,我会去了解一下,谢谢。我以为你是在指 <bean> 内部的 <property> 元素。至于你的问题,我基本上会将许多模型参数存储在其中(例如,numberOfTrials=50,等等[数值])。 - João Silva
<property>元素是您放置属性文件名称的位置;然后在类内部,您将有一个相应的setter,以Resource作为参数。就模型参数而言,它们可能是适合通过<property>设置的好候选项,也可能不是好的候选项-这取决于它们是否具有合理的“默认值”或者是用户必须指定的内容。您可以查看PropertyPlaceholderConfigurer或PropertyOverrideConfigurer:http://static.springsource.org/spring/docs/2.5.x/reference/beans.html,它们作为属性文件和通过上下文设置的`<property>`之间的桥梁。 - ChssPly76

1

有几个属性文件的位置,并将它们(一个接一个地)加载到单个属性对象中。这种方案允许映射具有默认值,然后可以在多个点上覆盖该值。


1
文件名可以很容易地通过应用程序的命令行传递。这可以通过两种方式完成,一种是作为 主方法的参数(在主类名之后),另一种是作为属性(正如 aperkins 所暗示的那样)使用 -D 标志

我知道这一点,但我需要我的应用程序在Web环境中运行。此外,我有许多文件名需要传递,并且每次创建新文件时都需要更改我的run.sh(或类似)脚本,使用那种方法是不可取的。 - João Silva
如果您硬编码了文件名,那么您将处于类似的位置。您可以在命令行上使用包含所需配置文件列表的文件名。 - akf

0
我建议避免使用文件和文件系统相关路径。通常最好使用类路径路径(嗯,没有双关语...),因为: - 它通过在运行时和测试时间之间隔离类加载器使您的代码可测试,这是任何体面构建系统经常执行的操作。 - 它使您的代码与位置无关,并允许您忽略操作系统问题。 - 它使您的代码在独立应用程序或容器(轻量级、servlet、应用服务器等)中工作相同。
您可以查看具有很好附加功能的PropertyResourceBundle,即它是区域设置感知的,因此您可以使用不同的区域设置定义不同的属性。请注意,Locale可以被滥用以提供独立于l10n或i18n问题的参数化,例如,我在一个项目中使用了“windows”和“linux”区域设置,因为您可以构造自己的Locale实例并将其传递给加载器。
或者您可以自己构建路径...
或者您可以从输入流加载您的属性:
      Properties prop = Properties.load(getClass().getResourceAsStream("/myprops"));

HTH.


Spring很好,但对于这样一个简单的功能可能有点过头了。您可以看一下PicoContainer,它在DI方面比Spring更轻量级一些。 - insitu
我可能忽略了你的问题并给出了不充分的答案。在你的特定情况下,我已经将要加载的属性托管到根属性文件中。无论如何,这些信息都必须存储在某个地方:硬编码在代码中或配置文件中。最好对所有内容使用相同的机制...但是,如果您的属性与类名相关联,最好使用第二种解决方案,但将属性存储在主源树之外以便于编辑,并在运行时将其添加到类路径中。 - insitu

0
过去,我通过系统属性加载属性 - 文件名通过系统属性传递,并加载该文件。如果系统属性未设置,则使用默认名称。如果文件不存在,则需要决定如何处理。
好处是有一个标准,但他们可以使用命令行参数覆盖其位置/名称。
这只是我的个人意见。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接