SpringBoot启动命令行参数【-D】和【--】的区别,启动命令和IDEA如何传递:VM参数、命令行参数、系统参数、环境变量参数、main方法参数

【-D】和【--】两种写法都可以在命令行传入参数,实现覆盖 application.properties 中的配置项,不过写法有些不同

【-D】虚拟机参数

以运行jar包为例,写法为:

 
 
# 参数写法为:-Dproperty=value
 
java -Dserver.port=1234 -jar app.jar
 

【-D】要放到 -jar 前面,否则参数无效

在idea中通过虚拟机选项这里传递:
image

代码中可以通过系统属性 System.getProperties() 获取

 
 
public static void main(String[] args) {
 
SpringApplication.run(App.class, args);
 
 
 
// 1234
 
System.out.println(System.getProperty("server.port"));
 
 
 
System.out.println("*****启动成功*****");
 
}
 

【--】命令行参数

从main方法的参数传入,springboot会对这种参数进行自动解析
写法为:

 
 
java -jar app.jar --server.port=4321
 

【--】参数不能放到前面,否则会报错
image
在idea中这么传递:
image

代码中是通过main函数参数 String[] args 传入
再通过SpringApplication.run(App.class, args)传入springboot进行解析的
可以通过实现 EnvironmentAware接口 注入环境对象,可以读取命令行参数

 
 
@SpringBootApplication
 
public class App implements EnvironmentAware {
 
 
 
static Environment environment;
 
 
 
public static void main(String[] args) {
 
SpringApplication.run(App.class, args);
 
 
 
// 1234
 
System.out.println(System.getProperty("server.port"));
 
// 4321 同名的命令行参数覆盖虚拟机参数
 
System.out.println(environment.getProperty("server.port"));
 
 
 
System.out.println(environment.getProperty("user.dir"));
 
 
 
System.out.println("*****启动成功*****");
 
}
 
// 注入环境对象
 
@Override
 
public void setEnvironment(Environment environment) {
 
App.environment = environment;
 
}
 
}
 

命令行参数与虚拟机参数同名的,以命令行参数优先

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)
@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官方文档,做了简单总结。然后找了一个命令行启动参数示例,可以对照着看:

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

还有一个也可参考:

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提供支持和解析的传参方式

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

java -Xms1G -Xmx1G -Dname=YourBatman_D -jar application.jar --spring.profiles.active=prod --name="YourBatman_--" age=18

运行示例程序,输出:

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命令行参数)填入下面参数试一下:

-Xms1G -Xmx1G -Dname=YourBatman_D

运行示例代码,输出:

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后面直接输入:

--spring.profiles.active=test

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

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

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

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

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

将它勾选上:

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

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

来吧,在此区域键入值

--name=YourBatman_-- age=18

运行示例代码,输出:

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就出马解决了这个问题。

在⑥区域写上参数:

name=YourBatman_ENV;age=18_ENV 

运行示例代码,输出:

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设置的值情况如下:

// ③ -D方式
-Dname=YourBatman_D -Dage=18_D

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

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

在IDEA将值放入对应区域:

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

运行示例代码,输出:

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

源代码库

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

posted @ 2024-04-03 16:16  CharyGao  阅读(697)  评论(0编辑  收藏  举报