[Java SE] 彻底搞懂Java程序的三大参数配置途径:系统变量与JVM参数(VM Option)/环境变量/启动程序参数args
0 序言
一次没搞懂,处处受影响。这个问题属于基础问题,但又经常踩坑,不得不重视一下了。
1 Java程序动态参数的配置途径:系统变量与JVM参数(VM Option) vs 环境变量 vs 启动程序参数args

IDEA中的配置位置
| 参数 | 使用方式 | 示例 | 代码获取方式 |
|---|---|---|---|
| 系统属性 | 由操作系统、JVM、应用程序主动设置 | System.setProperties(Properties propes) / System.setProperties(String key,String value) / System.getProperties().load(String filename) / ... | String value = System.getProperty(propertyName); |
| VM Options(JVM参数) | 优先级高于系统变量。必须以-D 、 -X 、 -XX 开头,每个参数用空格隔开 |
-Dvm.key=VmKey -Dvm.key2=VmKey2 |
String key = System.getProperty(vm.key); |
| Program Arguments | 每个参数用空格隔开 | p.key=Program_Key p.name=ProgramName p.age=18 |
main(String[] args) |
| Environment Variable(环境变量) | 在我的电脑-属性-高级环境设置-环境变量内配置系统属性。其优先级低于 VM options ,即如果VM options 有一个变量和 Environment variable中的变量的key相同,则以VM options 中为准, 以分号分割多个 |
env.key=env_james;server.servlet.context-path=/test;server.port=8080 |
String envKey = System.getenv(“env.key”); |
2 工具类:SystemVariableTool
import cn.xx.bd.xx.common.debug.Print;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.DefaultApplicationArguments;
import org.springframework.util.ObjectUtils;
import java.util.*;
/**
* @author johnny-zen
* @version v1.0
* @create-time 2023/6/9 9:57
* @description 系统属性读取工具
* [VM options]
* VM options其实就是我们在程序中需要的运行时环境变量,它需要以-D或-X或-XX开头,每个参数使用空格分隔
* 使用最多的就是-Dkey=value设定系统属性值,比如-Dspring.profiles.active=dev3
* [Program arguments]
* Program arguments为我们传入main方法的字符串数组args[],它通常以--开头,如--spring.profiles.active=dev3
* 等价于-Dspring.profiles.active=dev3如果同时存在,以Program arguments配置优先
* @refrence-doc
* @gpt-promt
*/
public class SystemVariableTool {
private final static Logger logger = LoggerFactory.getLogger(SystemVariableTool.class);
public static final String SYSTEM_PROPERTY_PARAM = "SYSTEM_PROPERTY";
public static final String ENVIRONMENT_VARIABLE_PARAM = "ENVIRONMENT_VARIABLE";
/** args **/
public static final String ARGS_PARAM = "ARGS_PARAM";
// 可选参数
public static final String OPTION_ARG_PARAM = "OPTION_ARG_VARIABLE";
// 非可选参数
public static final String NON_OPTION_ARG_PARAM = "NON_OPTION_ARG_PARAM";
private ApplicationArguments applicationArguments;
public SystemVariableTool(ApplicationArguments applicationArguments){
this.applicationArguments = applicationArguments;
}
/**
* 读取系统属性
* @param propertyName
* @config-method 配置方法
* 1 ) IDEA - (Select one Program) - Edit Configurations - VM Options - ( "-Dserver.port=8088" / "-Xmx239m" )
* @sample
* server.port
* -----------------------------
* java.version Java 运行时环境版本
* java.vendor Java 运行时环境供应商
* java.vendor.url Java 供应商的 URL
* java.home Java 安装目录
* java.vm.specification.version Java 虚拟机规范版本
* java.vm.specification.vendor Java 虚拟机规范供应商
* java.vm.specification.name Java 虚拟机规范名称
* java.vm.version Java 虚拟机实现版本
* java.vm.vendor Java 虚拟机实现供应商
* java.vm.name Java 虚拟机实现名称
* java.specification.version Java 运行时环境规范版本
* java.specification.vendor Java 运行时环境规范供应商
* java.specification.name Java 运行时环境规范名称
* java.class.version Java 类格式版本号
* java.class.path Java 类路径
* java.library.path 加载库时搜索的路径列表
* java.io.tmpdir 默认的临时文件路径
* java.compiler 要使用的 JIT 编译器的名称
* java.ext.dirs 一个或多个扩展目录的路径
* os.name 操作系统的名称
* os.arch 操作系统的架构 例如: "amd64"
* os.version 操作系统的版本 例如: "10.0"
* file.separator 文件分隔符(在 UNIX 系统中是"/")
* path.separator 路径分隔符(在 UNIX 系统中是":")
* line.separator 行分隔符(在 UNIX 系统中是"/n")
* user.country 用户所在国家
* user.name 用户的账户名称
* user.home 用户的主目录 例如: "C:\Users\Johnny"
* user.dir 用户的当前工作目录 例如: "E:\source_code\BigData\bdp_common_data_service"
* user.language 用户当前的语言 例如: "zh"
* user.timezone 用户所在时区 例如: "Asia/Shanghai"
* @return
*/
public static String getSystemProperty(String propertyName){
Map enviromentProperties = System.getProperties();
return (String) enviromentProperties.get(propertyName);
}
/**
* 读取环境变量
* @config-method 配置方式 :
* 优先级 : 方式1 < 方式2
* 1) My Computer - 属性 - 高级系统设置 - 环境变量 - ...
* 2) IDEA - (Select one Program) - Edit Configurations - Environment Variables - ( ENV_VAR="env-var-demo" server.port=8090 ...)
*
* @sample
* USERPROFILE :用户目录
* USERDNSDOMAIN :用户域
* PATHEXT :可执行后缀
* JAVA_HOME :Java安装目录
* TEMP :用户临时文件目录
* SystemDrive :系统盘符
* ProgramFiles :默认程序目录
* USERDOMAIN :帐户的域的名称
* ALLUSERSPROFILE :用户公共目录
* SESSIONNAME :Session名称
* TMP :临时目录
* Path :path环境变量
* CLASSPATH :classpath环境变量
* PROCESSOR_ARCHITECTURE :处理器体系结构
* OS :操作系统类型
* PROCESSOR_LEVEL :处理级别
* COMPUTERNAME :计算机名
* Windir :系统安装目录
* SystemRoot :系统启动目录
* USERNAME :用户名
* ComSpec :命令行解释器可执行程序的准确路径
* APPDATA :应用程序数据目录
* @return
*/
public static String getEnvironmentVariable(String variableName){
Map enviromentProperties = System.getenv();
return (String) enviromentProperties.get(variableName);
}
public Map<String, Object> getVariables(String variableName){
Map<String, Object> resultMap = new HashMap<>();
String systemProperty = getSystemProperty(variableName);
resultMap.put(SYSTEM_PROPERTY_PARAM, systemProperty);
String environmentVariable = getEnvironmentVariable(variableName);
resultMap.put(ENVIRONMENT_VARIABLE_PARAM, environmentVariable);
//解析 args
String argsValue = null;
String[] args = applicationArguments.getSourceArgs();
if(!ObjectUtils.isEmpty(args)){
for(int i = 0; i < args.length; i++){
if(args[i].toLowerCase().contains(variableName.toLowerCase())){
argsValue = args[i];
}
}
}
resultMap.put(ARGS_PARAM, argsValue);
/**
* 解析选项参数
* @description
* 1. 不同框架 对 args 的解析策略均不同。例如 Flink 的 ParameterTool 与 SpringBoot 的 DefaultApplicationArguments,解析规则和解析结果有很大差异
* 1. 基于 SpringBoot 的 ApplicationArguments 接口, DefaultApplicationArguments 。 如果是以”--“为前缀,则判定为选项参数;反之,被判定为 非选项参数
* @sample
* [1] 选项参数的有效示例
* --foo
* --foo=
* --foo=""
* --foo=bar
* --foo="bar then baz"
* --foo=bar,baz,biz
* [2] 选项参数的无效示例
* -foo
* --foo bar
* --foo = bar
* --foo=bar --foo=baz --foo=biz
*/
List<String> optionArgs = applicationArguments.getOptionValues(variableName);// args = { "--foo="bar then baz" } , variableName = "foo" => optionArgs = {"bar then baz"}
resultMap.put(OPTION_ARG_PARAM, optionArgs);
List<String> allNonOptionArgs = applicationArguments.getNonOptionArgs();// { "server.port=8089" , "server.port=8090", "boo=bar,then,baz" , "foo=bar then baz" }
List<String> nonOptionArgs = new ArrayList<>();
for(int i=0;i<allNonOptionArgs.size();i++){
if(allNonOptionArgs.get(i).toLowerCase().contains(variableName.toLowerCase())){
nonOptionArgs.add( allNonOptionArgs.get(i) );
}
}
resultMap.put(NON_OPTION_ARG_PARAM, nonOptionArgs);
return resultMap;
}
public static void main(String[] args) {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
SystemVariableTool systemPropertiesUtil = new SystemVariableTool(applicationArguments);
Map<String, Object> map = systemPropertiesUtil.getVariables("server.port");
Print.print(map);
}
}
X 参考文献
[Java SE] 彻底搞懂Java程序的三大参数配置途径:系统变量与JVM参数(VM Option)/环境变量/启动程序参数args的更多相关文章
- 一文彻底搞懂Java中的环境变量
一文搞懂Java环境变量 记得刚接触Java,第一件事就是配环境变量,作为一个初学者,只知道环境变量怎样配,在加上各种IDE使我们能方便的开发,而忽略了其本质的东西,只知其然不知其所以然,随着不断的深 ...
- 一文搞懂Java引用拷贝、浅拷贝、深拷贝
微信搜一搜 「bigsai」 专注于Java和数据结构与算法的铁铁 文章收录在github/bigsai-algorithm 在开发.刷题.面试中,我们可能会遇到将一个对象的属性赋值到另一个对象的情况 ...
- 一文搞懂Java引用拷贝、深拷贝、浅拷贝
刷题.面试中,我们可能会遇到将一个对象的属性赋值到另一个对象的情况,这种情况就叫做拷贝.拷贝与Java内存结构息息相关,搞懂Java深浅拷贝是很必要的! 在对象的拷贝中,很多初学者可能搞不清到底是拷贝 ...
- 【Java SE】如何用Java实现直接选择排序
摘要:直接选择排序属于选择排序的一种,但是它的排序算法比冒泡排序的速度要快一些,由于它的算法比较简单,所以也比较适合初学者学习掌握. 适宜人群:有一定Java SE基础,明白Java的数据类型,数组的 ...
- 【Java SE】如何用Java实现插入排序
摘要:前面三期分别写了三篇简单排序的算法,今天来讲一点稍微难一点的排序算法-----插入排序. 基本思想: 设n个数据已经按照顺序排列好(假定从小排到大). 输入一个数据x,将其放在恰当的位置,使其顺 ...
- 【Java SE】如何用Java实现反转排序
摘要:反转排序是将原先已经排序好了的重新排序,是原来的数组元素的顺序反转过来.假设原来的数组顺序是{6,5,4,3,2,1},反转之后的顺序就是{1,2,3,4,5,6}.这个排序的算法不是很难,代码 ...
- 一篇文章搞懂高级程序员、架构师、技术总监、CTO从薪资到技能的区别
一篇文章搞懂高级程序员.架构师.技术总监.CTO从薪资到技能的区别 http://youzhixueyuan.com/senior-programmers-architects-technical-d ...
- 轻松搞懂Java中的自旋锁
前言 在之前的文章<一文彻底搞懂面试中常问的各种“锁”>中介绍了Java中的各种“锁”,可能对于不是很了解这些概念的同学来说会觉得有点绕,所以我决定拆分出来,逐步详细的介绍一下这些锁的来龙 ...
- 一文带你搞懂java中的变量的定义是什么意思
前言 在之前的文章中,壹哥给大家讲解了Java的第一个案例HelloWorld,并详细给大家介绍了Java的标识符,而且现在我们也已经知道该使用什么样的工具进行Java开发.那么接下来,壹哥会集中精力 ...
- [Java集合] 彻底搞懂HashMap,HashTable,ConcurrentHashMap之关联.
注: 今天看到的一篇讲hashMap,hashTable,concurrentHashMap很透彻的一篇文章, 感谢原作者的分享. 原文地址: http://blog.csdn.net/zhanger ...
随机推荐
- aspnetcore中aop的实现
aaspnetcore开发框架中实现aop不仅仅在业务上,在代码的优雅简洁和架构的稳定上都有着至关重要. 下面介绍三种用过的. 第一种通过System.Reflection的DispatchProxy ...
- Qt连接不上Linux服务器?
目录 1. Qt连接代码 2. 问题分析(按照顺序排除) 2.1 服务器IP是否能被Ping通? 2.2 客户端中的服务器IP和Port是否填写正确? 2.3 Linux的代码处理是否正确? 2.4 ...
- 机器学习(三):朴素贝叶斯+贝叶斯估计+BP人工神经网络习题手算|手工推导与习题计算
1.有 1000 个水果样例. 它们可能是香蕉,橙子或其它水果,已知每个水果的 3 种特性:是否偏长.是否甜.颜色是否是黄色 类型 长 不长 甜 不甜 黄色 非黄 Total 香蕉 400 100 3 ...
- 基于Admin.NET框架的前端的一些改进和代码生成处理(2)
在上篇随笔<基于Admin.NET框架的前端的一些改进和代码生成处理(1)>中大致介绍了一些关于对Admin.NET框架的前端的改造工作,主要目的就是希望能够增加前端代码的简洁性和可读性, ...
- 各类电商平台批量获取商品信息 API 详细操作说明
前言获取商品信息可以更加快捷的查看商品的详请参数,同理批量获取商品信息的话就可以查看多个商品的信息参数,便于我们查看整个店铺的数据情况方便运营管理.具体操作如下:先获取一个key和secret,登入测 ...
- Chrome浏览器插件:CrxMouse(鼠标手势控制浏览器)
CrxMouse是一款谷歌浏览器插件,它可以通过手势来控制您的浏览器,在您的日常网络浏览中提高效率和速度. 插件介绍 CrxMouse是一个非常流行的谷歌浏览器插件,它允许您通过鼠标手势来控制您的浏览 ...
- Python 3.11.官方文档
索引 模块 | Python » English Spanish French Japanese Korean Brazilian Portuguese Simplified Chinese Trad ...
- day05-SpringCloud Eureka-服务注册与发现02
SpringCloud Eureka-服务注册与发现02 3.搭建EurekaServer集群-实现负载均衡&故障容错 3.1为什么需要集群EurekaServer? 微服务RPC远程服务调用 ...
- Solon2 之 Groovy 语言开发后端接口项目
今天再做个新的尝试,用 Solon 框架写个 Groovy 后端项目.借助 "Solon Initializr" 生成个项目模板,会比较方便. 1.生成项目模板 打开"S ...
- vite项目优化----- 解决终端optimized dependencies changed. reloading问题
写在前面网上都说vite要比webpack快,但个人感受,默认情况下, vite项目的启动确实比webpack快,但如果某个界面是首次进入,且依赖比较多/比较复杂的话,那就会比较慢了. 这篇文章就是用 ...