Java System.getProperty VS. System.getenv(译)
原文: Java System.getProperty vs System.getenv
1、简介
Java 应用代码中会自动引入 java.lang
包。这个包包含很多常用的类,包括 NullPointerException
、 Object
、 Math
、 String
等等。
其中 java.lang.System
类是一个 final 类,这意味着开发者无法继承它,其所有方法都是静态的(static)。
System 类中有两个方法,分别来 读取系统属性(system properties)和环境变量(environment variables)
,下面我们来看看这两者的区别。
2、使用 System.getProperty()
Java 平台使用一个 Properties
对象来提供 本地系统相关的信息和配置
,我们称之为 系统属性
。
系统属性包括当前用户、当前 Java 运行时版本 以及 文件路径分隔符诸如此类的信息。
如下代码中,我们使用 System.getProperty("log_dir")
来读取 log_dir
属性值。我们也会使用默认值参数,这样如果属性不存在, getProperty
则返回 /tmp/log
:
String log_dir = System.getProperty("log_dir", "/tmp/log");
如果希望在运行时变更系统属性,则可以使用 System.setProperty
方法:
System.setProperty("log_dir", "/tmp/log");
我们可以以如下格式使用命令行参数向应用传递指定属性或配置值:
java -jar jarName -DpropertyName=value
比如 将 app.jar 的 foo 属性值设置为 bar:
java -jar app -Dfoo="bar"
System.getProperty 返回的一定是一个字符串。
3、使用 System.getenv()
环境变量是类似 Properties 的一些 键/值 对。许多操作系统都提供环境变量的方式向应用传递配置信息。
设置环境变量的方式,各操作系统之间有所不同。例如,Windows 中,我们使用控制面板中的系统工具(System Utility)应用来设置,而 Unix 系统则使用 shell 脚本。
创建一个进程时,该进程默认会从其父进程继承一个克隆的上下文环境。
如下代码片段演示:使用一个 lambda 表达式来输出所有环境变量。
System.getenv().forEach((k, v) -> { System.out.println(k + ":" + v); });
getenv() 返回一个只读的 Map
。尝试向该映射中添加值,会抛出 UnsupportedOperationException
异常。
可以使用变量名称作为参数调用 getenv
来获取单个变量值:
String log_dir = System.getenv("log_dir");
此外,我们可以在应用中创建一个新进程,并向其上下文环境中添加新的环境变量。
Java 中,我们使用 ProcessBuilder
类来创建新进程,该类有一个名为 environment
的方法,此方法返回一个 Map
,不过这个映射不是只读的,这样就可以向其添加新元素:
ProcessBuilder pb = new ProcessBuilder(args); Map env = pb.environment(); env.put("log_dir", "/tmp/log"); Process process = pb.start();
4、区别
这两者本质上都是提供 字符串类型 键值 信息的映射,区别在于:
- 我们可以在运行时变更 系统属性(Properties),但是 环境变量(Environment Variables)仅是操作系统环境变量的一个不可变拷贝。
- 仅 Java 平台包含这个 系统属性 特性,而 环境变量 则是操作系统层面提供,全局可用的 – 运行在同一个机器上的所有应用都可以访问。
- 系统属性 在打包应用时就必须存在,而 环境变量 则任意时刻都可以在操作系统中创建。
5、总结一下
虽然这两者在概念上比较相似,但是 系统属性 和 环境变量 的应用方式差别很大。
二选一通常考量的是生效范围。使用 环境变量,同一个应用可以部署到多个机器上运行不同的实例,并在操作系统级别或者在 AWS / Azure 云平台控制台中进行配置,以免更新配置时还得重新构建应用( 译注:其实使用 系统属性 也可以实现这个效果,比如在 shell 脚本中获取系统环境变量,然后作为系统属性通过 Java 命令行参数传递给应用
)。
getProperty
方法名称是驼峰风格,但 getenv
不是,谨记!