【问题标题】:Best Practice for Using Java System Properties使用 Java 系统属性的最佳实践
【发布时间】:2009-01-28 13:21:28
【问题描述】:

我们的代码使用了很多系统属性,例如“java.io.tmpdir”、“user.home”、“user.name”等。我们没有在任何地方为这些定义任何常量(Java I 也没有) think) 或任何其他巧妙的方法来处理它们,以便它们以纯文本形式散布在整个代码中。

String tempFolderPath = System.getProperty("java.io.tmpdir");

每个人都如何使用系统属性?

【问题讨论】:

    标签: java properties


    【解决方案1】:

    我会像对待散布在代码中的任何其他 String 常量一样对待它,并为它定义一个常量变量。当然,在这种情况下,“java.io.tmpdir”不太可能改变,但你永远不知道。 (我并不是说 Sun 可能会改变“java.io.tmpdir”的含义,或者它指向的系统属性,而是您可能会改变对需要读取的系统属性的想法。)

    如果您只在一个类中使用特定属性,那么我会在该类中定义常量。

    private final String TEMPDIR = "java.io.tmpdir";
    

    如果您在不同的类中使用相同的属性,您可能需要定义自己的静态类来保存您最常使用的常量。

    public final Class Prop {
        public static final String TEMPDIR = "java.io.tmpdir";
        ...
    }
    

    然后,在任何需要使用该常量的地方,只需调用它使用

    System.getProperty(Prop.TEMPDIR);
    

    【讨论】:

    • 但是你会在哪里做呢?使某种常量仅在某处仅用于系统属性的接口?从来都不是他们的忠实粉丝。有什么建议吗?
    • 我添加了几个不同的建议,但我认为对于很多不同类中的常量字符串,你描述的接口是最好的方法。
    【解决方案2】:

    SystemUtils由Apache Commons Lang包提供,解决了这个问题。

    SystemUtils已经为大部分系统属性定义了常量,可以通过查找获得,例如:

    import org.apache.commons.lang3.SystemUtils;
    
    class Something
    {
        public static void main(String[] args){     
            System.out.println(SystemUtils.JAVA_IO_TMPDIR);
        }
    }
    

    也许,这是一种更清洁的方式。

    【讨论】:

      【解决方案3】:

      如果您在多个地方使用它,最好编写一个类来封装读取属性和其他属性。

      所以可能类似于:Configuration.getTemporaryDirectory()

      【讨论】:

        【解决方案4】:

        由于问题标题非常宽泛,我将提出另一个在使用系统属性时应考虑的良好做法。 SecurityManager 可以拒绝访问系统属性,因此您可能需要通过 PrivilegedAction, 访问它们,如下所示:

        String tmpdir = AccessController.doPrivileged(new PrivilegedAction<String>() {
          public String run() {
            return System.getProperty("java.io.tmpdir");
          }
        });
        

        当您的代码限制敏感操作时使用特权操作,这样即使恶意代码调用它也是安全的。

        例如,在 OutputStream open(File file) 这样的方法中使用特权操作是不安全的。不受信任的代码可以调用它,并使用您代码的权限在任何地方编写任何内容。

        但是,如果您有一种方法可以将应用程序的用户首选项保存到您选择的文件中,那可能是安全的。恶意调用者无法选择文件位置或其内容;这些由您的代码指定。因此,您的方法可以使用特权操作来允许非特权代码调用它。

        【讨论】:

          【解决方案5】:

          我认为在面向对象的软件中,您可能有一个对象(或方法)依赖于必须完成工作的目录。因此,您可以证明这种对构造函数或方法的依赖。 之后,如果您需要该目录的默认值并且默认值来自系统属性,您可以简单地创建一个工厂方法或构造函数/方法,并将更少的参数传递给另一个成本运行器/方法:

          new File(System.getProperty("java.io.tmpdir");
          

          你不需要创建一个“依赖磁铁”来包含一个配置参数。

          【讨论】:

            【解决方案6】:

            我会将它们视为任何其他常量,可能带有P_PROP_ 前缀,并将它们放在适当的常量类中。

            如果你使用很多,我什至会考虑将它们拆分为 PropertyNames 常量类:

            public final class PropertyNames
            {
              private PropertyNames()
              {
                 // no instantiation
              }
            
              public static final String P_VAR_DIRECTORY = "org.acme.app.varDir";
            
              public static final String P_TMP_DIRECTORY = "java.io.tmpDir";
            }
            

            最后,我会认真考虑使用用于包的标准反向域名对属性名称本身进行命名空间。这只是为了避免与第三方属性消费者发生冲突。

            【讨论】:

            • 这些属性不是我定义的,它们是系统属性,我不能命名它们。
            【解决方案7】:

            在Java中,字符串是不可变的,这意味着内存空间中的同一个对象不会被覆盖;每次都会创建一个新字符串。目前投票率最高的建议是使用常量:

            System.getProperty(Prop.TEMPDIR);
            

            不幸的是,所使用的常量用于实际的属性键。这意味着每次您进行此调用时,您都将创建一个新的 String 对象来保存该值。在我看来,您应该将常量作为调用本身的结果:

            public static final String SYS_PROP_TEMP_DIR = System.getProperty("java.io.tmpdir");
            

            【讨论】:

            • 这是不正确的:您没有创建字符串,而是 JRE 返回对字符串的引用,它很可能会在后续调用中为您提供相同的引用,而不是重新创建它。但是,仍然值得按照您的建议进行操作,因为 System.getProperty() 调用显然很慢:stackoverflow.com/a/18045622/587365
            • 另外,封装您从系统属性获取此信息这一事实也没有什么坏处。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-04-23
            • 1970-01-01
            • 2011-01-27
            • 2010-09-22
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多