前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【方向盘】启动命令和IDEA如何传递:VM参数、命令行参数、系统参数、环境变量参数、main方法参数

【方向盘】启动命令和IDEA如何传递:VM参数、命令行参数、系统参数、环境变量参数、main方法参数

作者头像
YourBatman
发布2022-09-16 14:17:51
3.7K0
发布2022-09-16 14:17:51
举报
文章被收录于专栏:BAT的乌托邦BAT的乌托邦
在这里插入图片描述
在这里插入图片描述

本文已被https://yourbatman.cn收录;女娲Knife-Initializr工程可公开访问啦;程序员专用网盘https://wangpan.yourbatman.cn;技术专栏源代码大本营:https://github.com/yourbatman/tech-column-learning

你好,这里是Java方向盘,我是方向盘(YourBatman),坐稳扶好,开始发车。

Title

Link

所属专栏

【方向盘】-IntelliJ IDEA

源代码

https://github.com/yourbatman/FXP-java-ee

程序员专用网盘公益上线啦,注册送1G超小容量,帮你实践做减法

https://wangpan.yourbatman.cn

Java开发软件包(Mac)

https://wangpan.yourbatman.cn/s/rEH0 提取码:javakit

女娲工程

http://152.136.106.14:8761

版本约定

[Mac OS 12.3],[iTerm2 3.4.15(zsh 5.8)],[IntelliJ IDEA 2021.3.3]

📚前言

传递参数时,再次感受到IDEA产品设计的伟大和人性化。

作为一枚javaer,对“VM参数、命令行参数、系统参数、环境变量参数、main方法参数”这些名词不陌生,但可能也不太熟悉,分不清楚:不知道怎么传?不知道优先级?

本文依旧具有实操性,提升基础技能,最重要的是:提高效率,留出时间陪朋友、陪家人、陪妹纸~

本文内容相对较长,如果你对中间分析过程不感兴趣,可直接此图拿走,或拉到文末看结论即可。

在这里插入图片描述
在这里插入图片描述

✍正文

Java应用最终被打为可执行的Jar包(war包不讨论)方可运行,此时能向应用传入参数的唯一方式是:命令行。为了尝试为你彻底讲解清楚,本文采用逐层递进的方式:

  1. 列出命令行里所有的传参方式
  2. 用示例代码演示不同传参方式的效果、优先级
  3. 使用IDEA模拟不同的传参方式
    1. 因为在开发过程中,我们不可能打出jar包后再调试,那样效率太低,而是将这一切都在IDE里完成

main方法是应用程序的入口,正好Spring Boot的入口就是main方法,而且它作为现代Java应用的基座,现今绝大部分应用都构建在它之上,因此本文基于Spring Boot应用进行讲解,更具有现实意义。

🌈准备工作

准备工作主要分为三部分:

  • 构建示例代码
  • 命令行里所有传参方式
  • IDEA模拟传参功能

🚀构建示例代码

为了让参数的效果更直观,笔者特意花了“很长时间”构建出代码示例,对本代码做出说明:

  • 以Spring Boot作为底座,构建在其之上
  • 只关注两个key的值:yourbatman.nameyourbatman.age
    • 由于自带的属性k-v众多,全打印输出将无法查看和对比,因此做了聚焦
  • 只关注三大属性源:系统属性(sysProp)、环境属性(sysEnv)、命令行属性(cli)
代码语言:javascript
复制
@SpringBootApplication
public class Application {

    private static final String NAME = "name";
    private static final String AGE = "age";

    public static void main(String[] args) {
        System.out.println("main方法的参数\t" + Arrays.toString(args));
        Runtime runtime = Runtime.getRuntime();
        System.out.println("堆内存能达到的最大值(Xmx可控制它)\t" + ofBytes(runtime.maxMemory()).toMegabytes() + "mb");
        System.out.println("堆内存当前获得的大小(Xms可控制它)\t" + ofBytes(runtime.totalMemory()).toMegabytes() + "mb");
        System.out.println("堆内存当前剩余大小\t" + ofBytes(runtime.freeMemory()).toMegabytes() + "mb");

        System.out.println("==========下面参数来自Java原生==========");
        Properties sysProp = System.getProperties();
        printFromJava("sysProp", sysProp);
        Map<String, String> sysEnv = System.getenv();
        printFromJava("sysEnv", sysEnv);

        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
        ConfigurableEnvironment environment = context.getEnvironment();
        MutablePropertySources propertySources = environment.getPropertySources();

        System.out.println("==========下面参数来自Spring属性源==========");
        System.out.println("激活的profile spring.profiles.active对应的值\t" + environment.getProperty("spring.profiles.active"));
        System.out.println("激活的profile\t" + Arrays.toString(environment.getActiveProfiles()));

        PropertySource<?> cliSource = propertySources.get(COMMAND_LINE_PROPERTY_SOURCE_NAME);
        printFromSpring("cli命令行", cliSource);
        PropertySource<?> sysEnvSource = propertySources.get(SYSTEM_ENVIRONMENT_BEAN_NAME);
        printFromSpring("sysEnv", sysEnvSource);
        PropertySource<?> sysPropSource = propertySources.get(SYSTEM_PROPERTIES_BEAN_NAME);
        printFromSpring("sysProp", sysPropSource);

        System.out.println("========================================");
        System.out.println(format("Spring属性源【最终】结果\tname:%s age:%s", environment.getProperty(NAME), environment.getProperty(AGE)));
    }


    private static void printFromJava(String mark, Map<?, ?> source) {
        System.out.println(format("Java原生【" + mark + "】结果\tname:%s age:%s", source.get(NAME), source.get(AGE)));
    }

    private static void printFromSpring(String mark, PropertySource<?> source) {
        if (source == null) {
            System.out.println(format("Spring属性源【" + mark + "】结果\tname:%s age:%s", null, null));
        } else {
            System.out.println(format("Spring属性源【" + mark + "】结果\tname:%s age:%s", source.getProperty(NAME), source.getProperty(AGE)));
        }
    }
}

当什么都不配置,运行示例代码,输出:

在这里插入图片描述
在这里插入图片描述

🚀命令行里所有传参方式

命令行:一般指命令提示符,是在操作系统中,提示进行命令输入的一种工作提示符,也叫DOS操作方式。英文:Command Line,简称CLI。下图是Mac的命令行:

在这里插入图片描述
在这里插入图片描述

命令行参数,顾名思义:在命令行里的参数,CLI parameter或者CLI argument。

为了解Java命令行能传递哪些参数,笔者特地翻阅了Oracle官方文档,做了简单总结。然后找了一个命令行启动参数示例,可以对照着看:

在这里插入图片描述
在这里插入图片描述

还有一个也可参考:

代码语言:javascript
复制
nohup java -jar ./$appName -Xmx2g -Xms2g -Xss1m -XX:MaxDirectMemorySize=4G -XX:+UseG1GC 
-XX:MaxGCPauseMillis=200 -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=40 -XX:+PrintGCDateStamps 
-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -XX:+HeapDumpOnOutOfMemoryError 
-XX:+DisableExplicitGC -XX:-OmitStackTraceInFastThrow -XX:+PrintCommandLineFlags -XX:+UnlockCommercialFeatures -XX:+FlightRecorder 
-Djava.net.preferIPv4Stack=true -Dfile.encoding=UTF-8 --apollo.meta=http://10.7.xxx.xxx:8888 > ./server.out 2>&1 &

Java命行令支持一些选项,大的方面可以分为以下几类:

  • 标准选项:最常用的,所有JVM的实现都支持。如
    • -help
    • -version
    • -verbose:gc 显示每个垃圾收集(GC)事件的信息
    • -javaagent:jarpath[=options] 加载java程序的agent
    • -jar filename 执行一个jar应用
    • -ea 启用断言。默认情况下,断言在所有的包和类中被禁用
    • -Dproperty=value 设置一个系统属性值(sysProp)。property是一个没有空格的字符串,value是一个字符串,如果value带有空格那么用引号将其括起来(如-Dfoo=“foo bar”)。这个使用得特别多~
  • 非标准选项:针对Java HotSpot虚拟机的通用选项,这类参数不是所有参数所有虚拟机都支持。如
    • -X 显示所有可用的-X选项的帮助
    • -Xnoclassgc 禁用类的垃圾收集(GC)。这可以节省一些GC时间,从而缩短应用程序运行时的中断时间。注意:这里指的类的回收,而非对象的回收。一般情况下不建议开启此选项
    • -Xbootclasspath:path 由分号;分隔的目录、JAR 文件和 ZIP 档案的列表,以搜索引导类文件。这些文件将代替JDK中包含的引导类文件
    • -Xloggc:filename 用于记录GC事件信息的文件,并将其重定向到该文件。写入该文件的信息类似于-verbose:gc的输出,一般情况下配置这个而非-verbose:gc
    • -Xmssize 可简写为-Xms,堆内存最小大小,如-Xms256m。可配合-XX:InitalHeapSize
    • -Xmxsize 可简写为-Xmx,堆内存最大大小,如-Xmx1G。它的效果等同于-XX:MaxHeapSize
    • -Xmnsize 可简写为-Xmn,堆内新生代的大小,如-Xmn256m。可配合-XX:NewSize和-XX:MaxNewSize
      • 堆内老生代大小就是-Xmx减去-Xmn
    • -Xsssize 可简写为-Xss,每个线程可使用的内存大小,如-Xss1m。它的效果等同于-XX:ThreadStackSize
      • 在相同物理内存下,减小这个值能生成更多的线程。但线程不宜过多,经验值是最大不要超过5k个线程
  • 高级运行时选项:控制JVM运行期行为。如
    • -XX:+FlightRecorder
    • -XX:MaxDirectMemorySize=size 如-XX:MaxDirectMemorySize=1m
    • -XX:ThreadStackSize=size 如-XX:ThreadStackSize=1024k
    • -XX:MaxInlineSize=size 如-XX:MaxInlineSize=35
    • -XX:+TraceClassLoading 启用类加载时的跟踪。默认情况下,该选项被禁用,类不被追踪
  • 高级JIT编译器选项:控制由Java HotSpot VM执行的动态即时编译(JIT)。
    • -XX:CICompilerCount=threads 用于编译的编译器线程数。如-XX:CICompilerCount=2
    • -XX:+Inline 启用方法内联。这个选项默认是启用的以提高性能。要禁用方法内联,设置为-XX:-Inline
    • -XX:MaxInlineSize=size 设置要被内联的方法的最大字节码大小。如-XX:MaxInlineSize=35m
  • 高级可服务性选项:提供了收集系统信息和进行广泛调试的能力。如
    • -XX:+HeapDumpOnOutOfMemoryError 当抛出java.lang.OutOfMemoryError异常时,通过使用堆分析器(HPROF),启用将Java堆转储到当前目录下的一个文件。配合使用使用-XX:HeapDumpPath选项明确设置堆转储文件路径和名称。默认情况下,该选项被禁用,当抛出OutOfMemoryError异常时,堆不会被转储
    • -XX:HeapDumpPath=path 默认情况下,该文件是在当前工作目录下创建的,文件名是java_pidpid.hprof,其中pid是导致错误的进程的标识符,但也可自定义。如-XX:HeapDumpPath=./java_pid%p.hprof-XX:HeapDumpPath=C:/log/java/java_heapdump.log,当然也可指定目录即可,如-XX:HeapDumpPath=./app/tmp
  • 高级GC选项:控制Java HotSpot VM如何进行垃圾收集(GC)。如
    • -XX:+DisableExplicitGC 禁止处理对System.gc()的调用。该选项默认为禁用,也就是允许System.gc()
    • -XX:+UseConcMarkSweepGC 启用旧一代的CMS垃圾收集器。默认情况下,这个选项是禁用的,收集器会根据机器的配置和JVM的类型自动选择
    • -XX:MaxMetaspaceSize=size 可以分配给类元数据的最大本地内存量。默认情况下,该大小不受限制。可看情况设置,如-XX:MaxMetaspaceSize=1G
      • 代替了Java 8之前的-XX:MaxPermSize
    • -XX:MetaspaceSize=size 分配的类元数据空间的大小,首次超过该大小时将触发垃圾收集
      • 代替了Java 8之前的-XX:PermSize
    • -XX:MaxTenuringThreshold=threshold 转入老生代的存活次数。一般的默认值是15(CMS是6),最大值是15。如果是0,则直接跳过新生代进入老生代
    • -XX:SurvivorRatio 新生代中两个survivor和eden的比值。默认值是8,表示两个servivor:eden = 2:8,或者servivor:servivor:eden = 1:1:8
    • -XX:NewRatio=ratio 新生代(eden + 2*servivor) 与老年代的比值,默认值是2,表示新生代:老年代 = 1:2
    • -XX:+PrintGCDetails 打印每个GC的详细信息。默认情况下,这个选项是禁用的
    • -XX:+PrintGCTimeStamps 在每个GC上打印时间戳。默认情况下,这个选项是禁用的
    • -XX:+UseG1GC 启用G1垃圾收集器。G1收集器被推荐给需要大堆(大小约为6GB或更大)且对GC延迟要求有限的应用,推荐显示开启
    • -XX:G1ReservePercent=percent 堆的百分比(0到50),作为上限保留,以减少G1收集器的推广失败的可能性。默认情况下,这个选项被设置为10%
    • -XX:MaxGCPauseMillis=time 目前暂停时间(以ms为单位)。JVM将尽最大努力来实现它。默认情况下,没有最大暂停时间的值
    • -XX:ParallelGCThreads=threads 年轻代和老年代中用于并行GC线程数。默认值取决于JVM可用的CPU的数量
    • -XX:ConcGCThreads=threads 设置用于并发GC的线程数。默认值取决于JVM可用的CPU的数量
      • ConcGCThreads = (ParallelGCThreads + 3)/4,这两个参数是JVM调优的重要手段之一
    • -XX:G1HeapRegionSize=size 堆被细分的区域的大小(1MB~32MB,且必须是2的N次幂),默认根据堆大小来确定(共被分为2048个region)

更多的命令行参数可参见权威Oracle官方文档:https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html

总结一下,命令行里启用java应用可以传参的方式:

  1. -X打头
  2. -XX打头
  3. -D打头的k-v

除此之外,还有两种传参方式也经常看到,统称为程序参数(由程序自己负责解析):

  1. --打头 Spring Boot提供支持和解析的传参方式
  2. 没有打头,直接k-v Spring Boot提供支持和解析的传参方式

下面用一条的启动命令行,完成描述这几种参数方式:

代码语言:javascript
复制
java -Xms1G -Xmx1G -Dname=YourBatman_D -jar application.jar --spring.profiles.active=prod --name="YourBatman_--" age=18

运行示例程序,输出:

代码语言:javascript
复制
main方法的参数	[--spring.profiles.active=prod, --name=YourBatman_--, age=18]
堆内存能达到的最大值(Xmx可控制它)	981mb
堆内存当前获得的大小(Xms可控制它)	981mb
堆内存当前剩余大小	966mb
==========下面参数来自Java原生==========
Java原生【sysProp】结果	name:YourBatman_D age:null
Java原生【sysEnv】结果	name:null age:null
==========下面参数来自Spring属性源==========
激活的profile spring.profiles.active对应的值	prod
激活的profile	[prod]
Spring属性源【cli命令行】结果	name:YourBatman_-- age:null
Spring属性源【sysEnv】结果	name:null age:null
Spring属性源【sysProp】结果	name:YourBatman_D age:null
========================================
Spring属性源【最终】结果	name:YourBatman_-- age:null

笔者在图上,标出了对应关系,以辅助你理解:

在这里插入图片描述
在这里插入图片描述

①和②这两种方式比较特殊,有些是单值方式(+表示开启,-表示禁用),有些是k-v方式。它们有个共同点:只接受指定的参数值,否则就启动报错,如下图所示:

指定的值有哪些?不同的JVM参照各自的官方文档介绍

在这里插入图片描述
在这里插入图片描述

可以看到,JVM并不认识-Xyourbatman.xxx这种key,因此启动不了。但值得注意的是,正常启动情况下,-X和-XX值是不会存在系统、环境属性里的,任何属性源里都没有。

①②③是“标准的”JVM参数,因此我们统称为VM Options,由JVM负责解析,时机非常靠前,配置错误影响JVM的启动。④和⑤属于程序参数,由引用负责解析,它们必须在JVM启动后才行,所以必须配置在 -jar xxx.jar的后面,这点一定要注意喽。否则启动不了:

在这里插入图片描述
在这里插入图片描述

程序参数是传递给了main方法的入参,应用程序再通过解析此入参而获得对应的值的。

🚀IDEA模拟传参功能

java启动Spring Boot应用的命令行共支持5种方式传参,在如此强大的IEDA面前,都是可以模拟的,熟练使用可大大提高开发、调试效率。

用于模拟传参的窗口,长这样:

Tips:若你的IDEA版本比较低的话,窗口长得不尽相同,但功能区大同小异

在这里插入图片描述
在这里插入图片描述

在这个窗口里,咋一看能传递参数的仅有VM options这一个地方可供我们输入。难道它一个承担了所有?

🚩在VM options区域传参

VM options区域(也叫CLI arguments命令行参数)填入下面参数试一下:

代码语言:javascript
复制
-Xms1G -Xmx1G -Dname=YourBatman_D

运行示例代码,输出:

代码语言:javascript
复制
main方法的参数	[]
堆内存能达到的最大值(Xmx可控制它)	981mb
堆内存当前获得的大小(Xms可控制它)	981mb
堆内存当前剩余大小	955mb
==========下面参数来自Java原生==========
Java原生【sysProp】结果	name:YourBatman_D age:null
Java原生【sysEnv】结果	name:null age:null
==========下面参数来自Spring属性源==========
激活的profile spring.profiles.active对应的值	null
激活的profile	[]
Spring属性源【cli命令行】结果	name:null age:null
Spring属性源【sysEnv】结果	name:null age:null
Spring属性源【sysProp】结果	name:YourBatman_D age:null
========================================
Spring属性源【最终】结果	name:YourBatman_D age:null

完美。从输出的结果中可以很清楚的看到,-Dkey=value属性值会进入到系统属性sysProp里和Spring环境中的sysProp属性源里。

①②③可以在这里输,那④⑤呢?上面有提到④⑤必须放在-jar xxx.jar的后面才行,在IDEA这个输入框里如何体现“后面”?这个时候如果你在VM options后面直接输入:

代码语言:javascript
复制
--spring.profiles.active=test

得到的必然是大大的报错:

在这里插入图片描述
在这里插入图片描述

那怎么办,难道IDEA不支持④⑤方式传参?

当然不是,既然④⑤属于程序参数,那就再找找喽。它藏在这里了:

在这里插入图片描述
在这里插入图片描述

将它勾选上:

在这里插入图片描述
在这里插入图片描述
🚩在Program arguments区域传参

上图中的Program arguments区域也可叫命令行参数,但更准确的叫法是程序参数:由应用程序负责去解析(而非JVM)。

来吧,在此区域键入值

代码语言:javascript
复制
--name=YourBatman_-- age=18

运行示例代码,输出:

代码语言:javascript
复制
main方法的参数	[--name=YourBatman_--, age=18]
堆内存能达到的最大值(Xmx可控制它)	3641mb
堆内存当前获得的大小(Xms可控制它)	245mb
堆内存当前剩余大小	233mb
==========下面参数来自Java原生==========
Java原生【sysProp】结果	name:null age:null
Java原生【sysEnv】结果	name:null age:null
==========下面参数来自Spring属性源==========
激活的profile spring.profiles.active对应的值	null
激活的profile	[]
Spring属性源【cli命令行】结果	name:YourBatman_-- age:null
Spring属性源【sysEnv】结果	name:null age:null
Spring属性源【sysProp】结果	name:null age:null
========================================
Spring属性源【最终】结果	name:YourBatman_-- age:null

可以看到,name这对k-v并没有放进Java原生的sysProp或者sysEnv内,而放在了Spring的命令行属性源(SimpleCommandLinePropertySource)里头。

另外,除了main方法参数以外,age这对k-v没在“任何地方”出现过。咦,怎么回事?难道就因为前面缺两道杠--吗?是的,既然是Spring应用程序负责解析,那自然需要遵守其规范嘛,参考类SimpleCommandLineArgsParser

在这里插入图片描述
在这里插入图片描述

这就很好理解为什么结果中输出了name这对k-v,而“忽视”了age这对k-v了。

Tips:age这对k-v其实也进入了Spring的命令行属性源(SimpleCommandLinePropertySource),只不过在non-option区,取值时不会被取出来而已

这么一来就全部清晰了:IDEA的VM Options区域负责模拟①②③传参方式,Program arguments区域模拟④⑤传参方式,齐活。

不知你有没有发现,还有一个sysEnv系统环境变量以及Spring的sysEnv属性源一直未被赋予过值,相信笔者肯定不会只是让它来陪跑的,肯定未完。是的,IDEA有能力对它进行赋值。只需勾选:

在这里插入图片描述
在这里插入图片描述

视窗新增环境变量传参输入区域:

在这里插入图片描述
在这里插入图片描述
🚩在Environment variables区域传参

什么叫环境变量?这对于技术人都不陌生,macOS/Linux系统使用echo $变量名可查看该环境下此变量的值,windows也有对应的查看方式。

应用运行在操作系统内,所以可以读到所有的环境变量。不同的应用获取到的值都是一样的。但很明显,当开发环境下咱程序需要一个环境变量时,若去操作系统层面添加实在太麻烦了,事后还得记得删除并且还无法做到应用间隔离。这时候IDEA就出马解决了这个问题。

在⑥区域写上参数:

代码语言:javascript
复制
name=YourBatman_ENV;age=18_ENV 

运行示例代码,输出:

代码语言:javascript
复制
main方法的参数	[]
堆内存能达到的最大值(Xmx可控制它)	3641mb
堆内存当前获得的大小(Xms可控制它)	245mb
堆内存当前剩余大小	233mb
==========下面参数来自Java原生==========
Java原生【sysProp】结果	name:null age:null
Java原生【sysEnv】结果	name:YourBatman_ENV age:18_ENV 
==========下面参数来自Spring属性源==========
激活的profile spring.profiles.active对应的值	null
激活的profile	[]
Spring属性源【cli命令行】结果	name:null age:null
Spring属性源【sysEnv】结果	name:YourBatman_ENV age:18_ENV 
Spring属性源【sysProp】结果	name:null age:null
========================================
Spring属性源【最终】结果	name:YourBatman_ENV age:18_ENV 

可以很清楚的看到,自定义环境变量属性值会进入到系统属性sysEnv里 Spring环境中的sysEnv属性源里。

在这里设置的环境变量,有且仅属于这个入口,其它应用or其它入口都获取不到它,真可谓使用方便并且隔离性还非常优秀,真不愧是IDEA。

Tips:命令行方式启动jar包时,无法为应用单独指定环境变量,此功能是IDEA为方便开发而“特制”的

🌈 命令行参数总结

当一个Spring Boot应用被打成jar后,使用命令行启动时,输入参数的方式共有5种,而IDEA共支持6种,它们的对应关系是:

命令行方式

IDEA方式

① -X

VM Options区域

② -XX

VM Options区域

③ -Dkey=value

VM Options区域

④ --key=value

Program arguments区域

⑤ key=value

Program arguments区域

Environment variables区域

另外,画了一张图作为总结:

在这里插入图片描述
在这里插入图片描述

🚀几种传参方式的值优先级

在命令行里传递自定义参数,总的来说有2种方式:

  • ③:-Dkey=value方式,去到sysProp和Spring的sysProp属性源
  • ④:–key=value方式,只去到Spring的命令行属性源

考虑到还有环境变量,因此这里也带它一起玩。笔者借助IDEA的能力,也往环境变量里放相同的key。

  • ⑥:环境变量方式,去到sysEnv和Spring的sysEnv属性源

不同区域,相同key设置的值情况如下:

代码语言:javascript
复制
// ③ -D方式
-Dname=YourBatman_D -Dage=18_D

// ④ --方式
--name=YourBatman_-- --age=18_--

// ⑥ 环境变量
name=YourBatman_ENV;age=18_ENV

在IDEA将值放入对应区域:

在这里插入图片描述
在这里插入图片描述

运行示例代码,输出:

代码语言:javascript
复制
main方法的参数	[--name=YourBatman_--, --age=18_--]
堆内存能达到的最大值(Xmx可控制它)	3641mb
堆内存当前获得的大小(Xms可控制它)	245mb
堆内存当前剩余大小	233mb
==========下面参数来自Java原生==========
Java原生【sysProp】结果	name:YourBatman_D age:18_D
Java原生【sysEnv】结果	name:YourBatman_ENV age:18_ENV
==========下面参数来自Spring属性源==========
激活的profile spring.profiles.active对应的值	null
激活的profile	[]
Spring属性源【cli命令行】结果	name:YourBatman_-- age:18_--
Spring属性源【sysEnv】结果	name:YourBatman_ENV age:18_ENV
Spring属性源【sysProp】结果	name:YourBatman_D age:18_D
========================================
Spring属性源【最终】结果	name:YourBatman_-- age:18_--

从“Spring属性源【最终】结果”来看,最终,④程序参数win

这从Spring属性源顺序上,很好理解这个结果:

在这里插入图片描述
在这里插入图片描述

④的属性源在“最”上面,优先级最高,所以最终win。

Tips:Spring Boot属性源是一套复杂的体系,是理解Spring Boot配置、配置中心的核心,本文不做展开

🚀概念解释

读完本文后,标题上涉及到的几个概念就很好解释了。

🚩VM参数

特指JVM虚拟机专用的参数,如-Xms -Xmx -XX:MaxMetaspaceSize=size等等,通过方式①②传递进来

🚩命令行参数

它是个统称,毕竟打成jar包后所有参数都只能通过命令行传递。

但是,在Spring Boot应用场景下,命令行参数常常特指commandLineArgs,也就是通过方式④⑤传递进来

🚩系统参数

系统级别的属性,存储在System.getProperties()和Spring的sysProp属性源里,通过方式③传递进来

🚩环境变量参数

命令行里启动jar包的方式无法为应用专门特定的传入环境变量参数,只能“改全局”的环境变量,所有应用共用。

但在开发场景下,使用IDEA可为应用定制,通过方式⑥传递进来

🚩main方法参数

它也是个统称:在-jar xxx.jar后面键入的所有参数都会被作为main方法参数传入进来,由应用程序自己负责解析。

Spring利用了这个特点,定了自己的规范--key=value用来传递参数到commandLineArgs属性源,优先级比sysProp和sysEnv都高。

🌈 提问

由于本文篇幅已经比较长了,但还有几个方面的知识点我觉得还没表述的,这里使用提问的方式列出来,想研究or实战这块的小伙伴可自己试试。

  1. 命令行参数、系统参数、环境变量等,他们的key区分大小写吗?
  2. 站在IDEA产品设计的角度,为何IDEA运行视窗只提供出VM Options区域让你输入?
  3. IDEA针对Spring应用的运行视窗,有一个Active profiles。如果这里写值,通过spring.profiles.active这个key能取到吗?通过environment.getActiveProfiles()呢?
在这里插入图片描述
在这里插入图片描述

🍞总结

通读本文下来,是否觉得终于有人把这些概念给撇清了。如果有,那就是本文的意义所在。

本文内容不难,但希望通过文字、案例来把它讲解得清楚,笔者还是狠下了一番功夫的,期待你的关注,留言交流。

本专栏上下文

我是方向盘(YourBatman):前25年不会写Hallo World、早已毕业的大龄程序员。高中时期《梦幻西游》骨灰玩家,网瘾失足、清考、延期毕业、房产中介、保险销售、送外卖…是我不可抹灭的黑标签

  • 🎓2013.07 清考、毕业答辩3次未通过、延期毕业
  • 🏷2013.08-2014.07 宁夏中介公司卖二手房1年,毕业后第1份工作
  • ️️🏷2014.07-2015.05 荆州/武汉,泰康人寿卖保险3月、饿了么送外卖2月,还有炸鸡排、直销等第2345份工作
  • 🏷2015.08 开始从事Java开发,闯过外包,呆过大厂!擅长抽象思维,任基础架构团队负责人
  • 🏷2021.08 因“双减政策”失业!历经9面,终获美团外卖L8的offer
  • 🙅🏻‍♀️Java架构师、Spring开源贡献者、CSDN博客之星年度Top 10、领域建模专家、写作大赛1/2届评委
  • 📚高质量代码、规范践行者;DDD领域驱动深度实践;即将出版书籍《Spring奇淫巧技》

序号

专栏名称

简介

01

【方向盘】-程序人生

程序人生,人生程序

02

【方向盘】-资讯/新特性

IDEA、JDK、Spring技术栈…新特性

03

【方向盘】-IntelliJ IDEA

熟练使用IDEA就相当拥有物理外挂,助你高效编码

04

【方向盘】-Bean Validation

熟练掌握数据校验,减少90%的垃圾代码

05

【方向盘】-日期时间

帮你解决JDK Date、JSR 310日期/其实 的一切问题

06

【方向盘】-Spring类型转换

Spring类型转换-框架设计的基石

07

【方向盘】-Spring static

static关键字在Spring里的应用

08

【方向盘】-Cors跨域

关于跨域请求问题,本专栏足矣

09

【方向盘】-Jackson

Almost Maybe是最好的Jackson专栏

10

【方向盘】-Spring配置类

专讲@Configuration配置类,你懂的

11

【方向盘】-Spring技术栈

暂无所属小分类的,Spring技术栈大分类

12

【方向盘】-JDK

暂无所属小分类的,JDK技术栈大分类

13

【方向盘】-Servlet

Servlet规范、Web相关内容专题

14

【方向盘】-Java EE

从Java EE到Jakarta EE,30年弹指一挥间

15

【方向盘】-工具/提效

开发工具、软件工具,目标是提效

16

【方向盘】-Spring技术栈新特性

Spring Framework、Spring Boot、Spring Cloud、Spring其它技术

17

【方向盘】-基本功

每个Javaer,都需要有扎实的基本功

99

源代码库

大多数专栏均配有源代码,都在这里

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-07-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 📚前言
  • ✍正文
    • 🌈准备工作
      • 🚀构建示例代码
      • 🚀命令行里所有传参方式
      • 🚀IDEA模拟传参功能
    • 🌈 命令行参数总结
      • 🚀几种传参方式的值优先级
      • 🚀概念解释
    • 🌈 提问
    • 🍞总结
      • 本专栏上下文
      相关产品与服务
      微服务引擎 TSE
      微服务引擎(Tencent Cloud Service Engine)提供开箱即用的云上全场景微服务解决方案。支持开源增强的云原生注册配置中心(Zookeeper、Nacos 和 Apollo),北极星网格(腾讯自研并开源的 PolarisMesh)、云原生 API 网关(Kong)以及微服务应用托管的弹性微服务平台。微服务引擎完全兼容开源版本的使用方式,在功能、可用性和可运维性等多个方面进行增强。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档