java命令启动java应用时首先会启动 java 运行时环境JRE,然后加载指定的类,调用类的 main 方法。在通过java命令启动应用时,有一系列的可选参数,按类别区分为系统参数和运行参数,它们在java命令中的位置与使用方式是有区别的,本教程主要介绍java命令中这2种参数的使用方式及区别,以及springboot项目中3大参数的用法。
1、java程序的入口方法
main()方法是java程序的入口方法,是JVM能够识别的特殊方法名,当程序开始运行时,Java虚拟机(JVM)会首先查找main()方法。该方法必须定义为 public static
类型,并且不返回任何值,参数为 String 类型的数组,最常用的定义形式为:public static void main(String[] args)
,还有一些其他的定义形式如下:
public static void main(String[] args)
static public void main(String[] args)
public static final void main(String[] args)
static public synchronized void main(String[] args)
2、java的启动参数
2.1 java程序的启动命令
java 命令支持两种启动方式,一种是指定要执行的 java 类,另一种是指定要执行的 jar 包,具体语法如下:
// 指定要执行的 java 类
java [options] classname [args]
// 指定要执行的 jar 包
java -jar [options] *.jar [args]
上述命令中每一项的含义如下:
- options 是可选项,选项之间使用空格分割,配置 java 系统参数
- classname 是要加载的类的名字
- filename 是要执行的 java 压缩文件(JAR)的名字,需要和 -jar 搭配使用
- args 是传递给 main() 方法的参数,使用空格分割,配置 java 运行参数
从上面的语法说明中可以看出来,在通过 java 命令启动应用时,有一系列的可选参数,包括系统参数和运行参数,使用时可以根据应用场景选择合适的参数。
2.2 系统参数(VM option)
java的系统参数(VM option)为java中的系统级全局变量,该参数在程序中任何位置都可以访问到。优先级最高,覆盖程序中同名配置。
要特别注意的是:该参数的位置是在java命令中的
classname
和*.jar
之前,要是放在java类或jar包后面是不起作用的。
2.2.1 系统参数的语法格式
系统参数的标准语法格式为:-Dargname=argvalue
,多个参数之间用空格隔开,如果参数值中间有空格,则用引号括起来。其中 argname
表示参数名,argvalue
表示参数值,-D
表示这个参数是java的系统参数,为固定写法,注意字母 D
必须大写。
参数名 argname
可以是 Java 默认的,此类参数由 JVM 虚拟机自动识别并生效,例如,-Dfile.encoding=UTF-8
用于指定文件编码格式;也可以是用户自定义的,例如,-Dmy=user
,程序中可以读取该参数值,执行相关逻辑。
系统参数中设置的参数键值对,在程序中可以用 System.getProperty("propertyName")
来获取对应的参数值。
2.2.2 系统参数的示例1 - 不带包名的java文件
首先创建一个名为 JavaParam.java
的文件,内容如下:
public static void main(String[] args) {
String result = System.getProperty("vmparam");
System.out.println("vmparam: " + result);
}
打开dos窗口,我们编译下该文件并带上系统参数 vmparam
执行一下看效果:
- 编译java文件
# cd到 JavaParam.java 文件所在的目录,执行下面的编译命令:
javac JavaParam.java
# 如果代码中有中文,因java文件的保存编码格式不同,有时会提示 “java编译命令 错误: 编码 GBK 的不可映射字符..”,可以在编译命令中指定编码格式如下
javac -encoding UTF-8 JavaParam.java
- 执行/运行生成的class文件,这里注意系统参数是在java文件的前面
java -Dvmparam=test JavaParam
2.2.3 系统参数的示例2 - 带包名的java文件
上述例子中的java代码没有包名(package),如果代码中包含包名,则java执行命令有所区别:
首先创建一个名为 JavaParam.java
的文件,与上例的区别仅仅是加了package包名,内容如下:
package com.test;
public class JavaParam {
public static void main(String[] args) {
String result = System.getProperty("vmparam");
System.out.println("vmparam: " + result);
}
}
有包的java程序,如果用上例的 java -Dvmparam=test JavaParam
命令来执行会失败,这是由于我们没有指定classpath,jvm准备在当前路径下查找JavaParam.class来装载,找了一圈没找到(确实有个JavaParam类,但是A类的完整路径是com.test.JavaParam,所以不是这个),报错找不到或无法加载主类。需要用完整包名来执行。
- 编译java文件,我们可以使用
-d .
来让编译器以当前路径为基准,自动创建包路径,这个-d .
放在命令的前面或后面都可以。
# cd到 JavaParam.java 文件所在的目录,执行下面的编译命令:
javac -d . JavaParam.java
# 也可以把 -d . 放在后面
javac JavaParam.java -d .
# 如果代码中有中文,因java文件的保存编码格式不同,有时会提示 “java编译命令 错误: 编码 GBK 的不可映射字符..”,可以在编译命令中指定编码格式如下
javac -encoding UTF-8 -d . JavaParam.java
- 执行/运行生成的class文件,这里注意系统参数是在java文件的前面。同时要指定java类的完整包名。
java -Dvmparam=test com.test.JavaParam
多个系统参数示例:
java -Dvmparam=test -Dfile.encoding=UTF-8 com.test.JavaParam
2.3 运行参数
main()方法执行时传入的参数值即为运行参数,如果参数有多个,用空格分开。main()方法的参数 String[] args
就是存储运行参数的变量,在程序中可以直接使用。
2.3.1 运行参数的语法格式
运行参数的标准语法格式为:argvalue
,只需要指定参数值即可,多个参数值之间用空格隔开,如果参数值中间有空格,则用引号括起来。
2.3.2 运行参数的示例
首先创建一个名为 JavaParam.java
的文件,内容如下:
package com.test;
public class JavaParam {
public static void main(String[] args) {
//获取系统参数
String vmParam = System.getProperty("vmOption");
System.out.println("vmOption的参数为:" + vmParam);
//获取main方法的参数即运行参数
for (int i = 0; i < args.length; i++) {
System.out.println("第" + (i+1) + "个参数为: " + args[i]);
}
}
}
- 编译java文件,我们可以使用
-d .
来让编译器以当前路径为基准,自动创建包路径,这个-d .
放在命令的前面或后面都可以。
# cd到 JavaParam.java 文件所在的目录,执行下面的编译命令:
javac -encoding UTF-8 -d . JavaParam.java
- 执行/运行生成的class文件,这里注意系统参数是在java文件的前面。同时要指定java类的完整包名。有3个运行参数a、b、c在java类的后面。
java -DvmOption=test com.test.JavaParam a b c
2.4 系统参数和运行参数的区别
通过上⾯的⽰例我们已经发现使⽤系统参数和运行参数时,系统参数是紧随 java
之后的(如果是执行的jar包,那就是跟在 java -jar
之)后。而运行参数则是跟在java类名 JavaParam
之后(如果是执行的jar包,那就是跟在 xxx.jar
之后)。如果不按照顺序执行,要么参数不被识别,要么就会报异常。
例如:java JavaParam -DvmOption=test
,这里的参数 -DvmOption=test
我们的本意是将 vmOption=test
作为系统参数,而这里程序是将 -DvmOption=test
整个作为运行参数的。
再举个例子:java a b c JavaParam
,我们将运行参数 a b c
放在执行类 JavaParam
的前面,则程序会报错“找不到或无法加载主类 a”。
2.5 IDEA 中的参数设置(系统参数和运行参数)
- 新建java文件
在idea中新建一个项目demo,在demo项目中新建一个名为 JavaParam.java
的文件,内容如下:
package com.kz.example.common.test;
/**
* java系统参数和运行参数
*/
public class JavaParam {
public static void main(String[] args) {
//获取系统参数
String vmParam = System.getProperty("vmParam");
System.out.println("vmParam的参数/系统参数为:" + vmParam);
//获取main方法的参数即运行参数
for (int i = 0; i < args.length; i++) {
System.out.println("第" + i + "个运行参数为: " + args[i]);
}
}
}
- IDEA 中的参数设置
通过菜单 Run -> Edit Configurations
打开配置页面,在Application下选中 JavaParam
类,点击 Modify options
,在展开的下拉列表中选中 Add VM options
选项,表示在配置列表中展示系统参数。
- 也可以在java类上右键选择
More Run/Debug
->Modify Run Configuration...
进入配置页面。
在 VM options
中设置系统参数,Program arguments
中设置运行参数。
系统参数设置为-DvmParam="hello" -Dfile.encoding=UTF-8
(可以设置1个或多个参数,多个参数以空格分开),运行参数设置为 aa bb cc dd
设置后的内容如下:
在java类上右键选择 run 'JavaParam.main()'
运行java,执行结果如下:
可以看到系统参数和运行参数都输出了期望的结果。
3、springboot的启动命令参数
3.1 springboot项目配置
假设我们有一个springboot项目(自己可以新建一个或利用已有的项目测试),配置文件application.yml 部分内容如下:
#端口,项目上下文
server:
port: 8080
servlet:
context-path: /demo
# springboot多环境配置
# 默认启动的是测试环境配置
spring:
profiles:
active: test
# 自定义的参数
myParam: on
可以使用命令 java -jar demo.jar
来启动Spring Boot项⽬,这时候项目的访问端口为8080。
可以在启动参数里修改配置文件中配置的参数。
我们也可以在命令中使用参数来指定端口号,如
java -jar demo.jar --server.port=8081
,这时配置文件中的8080端口就不起作用了,项目是以8081的端口启动,可见通过命令⾏传递的参数具有更⾼的优先级,会覆盖同名的其他配置参数。
默认情况下Spring Boot使⽤8080端⼝,通过上述参数将其修改为8081端⼝,⽽且通过命令⾏传递的参数具有更⾼的优先级,会覆盖同名的其他配置参数。
启动Spring Boot项⽬时传递参数,有三种参数形式:
- 选项参数
- ⾮选项参数/运行参数
- 系统参数
3.2 选项参数
选项参数,也叫命令行参数,在启动Spring Boot项⽬时,我们可以通过选项参数来传递项目的一些配置参数:
java -jar xxx.jar --server.port=8081
这时配置文件中的8080端口就不起作用了,项目是以8081的端口启动,可见通过命令⾏传递的参数具有更⾼的优先级,会覆盖同名的其他配置参数。这里的 --server.port=8081
就是选项参数。通过 --server.port
来设置应⽤程序的端⼝。其配置作⽤等价于在application.properties中配置的 server.port=8081
,但是优先级会更高。
- 选项参数的基本格式为
--name=value
(注意这里“–”为连续的两个减号)。
选项参数的获取
选项参数可以直接通过 @Value
注解在类中获取,该注解的参数形式为 ${paramName}
,示例如下:
@RestController
public class ParamController {
@Value("${server.port}")
private String serverPort;
}
选项参数和⾮选项参数均可以通过ApplicationArguments接⼝获取,具体用法参考非选项参数/运行参数部分。
3.3 ⾮选项参数/运行参数
⾮选项参数的使⽤⽰例如下:
java -jar xxx.jar abc def
上述⽰例中,“abc”和“def”便是⾮选项参数,也叫运行参数。
⾮选项参数/运行参数的获取
选项参数和⾮选项参数(也叫运行参数)均可以通过 ApplicationArguments 接⼝获取,具体获取⽅法直接在使⽤参数的类中注⼊ ApplicationArguments
接⼝即可,具体示例如下。
//此处springboot启动的时候传入参数
SpringApplication.run(Application.class, args);
@RestController
public class ArgumentsController {
@Resource
private ApplicationArguments arguments;
// 获取参数
public void getArgs() {
List<String> params = arguments.getNonOptionArgs();
for(int i=0;i<params.size();i++){
System.out.println(params.get(i));
}
}
}
3.4 系统参数
系统参数,该参数会被设置到系统变量中,系统参数的标准语法格式为:-Dargname=argvalue
,多个参数之间用空格隔开,如果参数值中间有空格,则用引号括起来。其中 argname
表示参数名,argvalue
表示参数值,-D
表示这个参数是java的系统参数,为固定写法,注意字母 D
必须大写。使⽤⽰例如下:
- 注意:通过
-D
传递系统参数时,务必放置在待执⾏的jar包之前。
java -jar -Dserver.port=8081 xxx.jar
系统参数的获取
系统参数可以通过java.lang.System提供的⽅法获取,具体如下:
String systemServerPort = System.getProperty("server.port");
3.5 参数的区别
关于参数的区别,重点看选项参数和系统参数。通过上⾯的⽰例我们已经发现使⽤选项参数和系统参数时,选项参数在命令中是位于 xxx.jar
之后传递的,⽽系统参数是紧随java -jar
之后的。如果不按照顺序执行,要么参数不被识别,要么就会报异常。
- 选项参数在命令中是位于
xxx.jar
之后传递的。 - 系统参数在命令中是紧随
java -jar
之后的。
⽐如使⽤如下⽅式使⽤选项参数:
java -jar --server.port=8081 xxx.jar
则会抛出如下异常:
Unrecognized option: --server.port=8081
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
如果将系统参数放在jar包后⾯,问题会更严重。会出现可以正常启动,但参数⽆法⽣效。这也是为什么有时候明明传递了参数但是却未⽣效,那很可能是因为把参数的位置写错了。
3.6 参数的优先级
对于同一个参数,我们可以使用不同的方式进行传递,如springboot的环境配置参数 spring.profiles.active
,既可以使用系统参数来传递,也可以使用选项参数来进行。
方式一:使用系统参数
java -jar -Dspring.profiles.active=prod demo.jar
执行上述命令时,如果我们在程序中输出参数 spring.profiles.active
和 myParam
的值,可以看到 spring.profiles.active
的值为 prod
,myParam
的值为 on
。这2个值在 application.yml 的配置为 test
和 on
,可以在 ## 3.1 springboot项目配置 部分查看具体配置。
可以看出,系统参数的优先级高于配置文件中定义的变量。
拓展:命令行的系统参数在配置文件中可以使用如下方式使用,如 spring.profiles.active:${spring.profiles.active}
,又如下例:
server:
port: 8080
servlet:
# 应用的访问路径,api.path可以由系统参数指定,这里表示访问路径默认取api.path的值,如果不存在则取 / 这个值。
context-path: ${api.path:/}
方式二:使用选项参数
java -jar demo.jar --spring.profiles.active=prod --myParam=off
执行上述命令时,如果我们在程序中输出参数 spring.profiles.active
和 myParam
的值,可以看到 spring.profiles.active
的值为 prod
,myParam
的值为 off
。
可以看出,选项参数的优先级高于配置文件中定义的变量。
方式三:同时使用系统参数和选项参数
java -jar -DmyParam='test1' demo.jar --spring.profiles.active=prod --myParam='test2'
执行上述命令时,如果我们在程序中输出参数 spring.profiles.active
和 myParam
的值,可以看到 spring.profiles.active
的值为 prod
,myParam
的值为 test2
。
可以看出,选项参数的优先级高于系统参数。
总结:
由上可以得出结论,Springboot加载参数的优先级如下:
配置文件变量 < 系统参数(JVM系统变量) < 选项参数(命令行参数)
3.7 IDEA中添加启动参数
通过菜单 Run -> Edit Configurations
打开配置页面,在Application下选中 JavaParam
类,点击 Modify options
,在展开的下拉列表中选中 Add VM options
选项,表示在配置列表中展示系统参数。
- 也可以在java类上右键选择
More Run/Debug
->Modify Run Configuration...
进入配置页面。
在 VM options
选项中填写系统参数 -Dspring.profiles.active=test -Dserver.port=8081
或者在 Environment variables
选项中填写选项参数(命令行参数) spring.profiles.active=test;server.port=8081
,二者选一即可(这两种写法的效果是一样的)。
上述方式对应的命令如下(即可以用下方的命令行直接启动应用),
第一种,只使用系统参数:
java -jar -Dspring.profiles.active=test -Dserver.port=8081 app.jar
第二种,只使用命令行参数
java -jar app.jar --spring.profiles.active=test --server.port=8081
第三种,混合使用系统参数和命令行参数
java -jar -Dspring.profiles.active=test app.jar --server.port=8081
评论区