ApplicationArguments 接口提供了对用于访问运行 SpringApplication 程序传递的参数。Spring Boot 提供了它的默认实现 DefaultApplicationArguments。例如:
public static void main(String[] args) { System.out.println(Arrays.toString(args)); ConfigurableApplicationContext context = SpringApplication.run( ApplicationargumentsDemoApplication.class, args); Environment environment = context.getEnvironment(); System.out.println("key1=" + environment.getProperty("key1")); System.out.println("key2=" + environment.getProperty("key2")); }
其中,args 是运行程序时动态传递过来的。如下图:
运行成功后将输出如下信息:
2020-11-09 13:01:51.141 INFO 12612 --- [ restartedMain] .s.a.ApplicationargumentsDemoApplication : Started ApplicationargumentsDemoApplication in 4.313 seconds (JVM running for 10.254) key1=val1 key2=val2
注意:上面 IDEA 的 “Run/Debug Configurations” 界面中的 “Program arguments” 输入框中输入的参数必须遵循 “--键=值” 的格式。
上面代码演示了使用 Environment 获取 run() 方法传递的 args 参数。下面将介绍通过注入 ApplicationArguments 对象来访问参数,如下:
package com.huangx.springboot.applicationarguments_demo2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Arrays; @RestController @SpringBootApplication public class ApplicationargumentsDemo2Application { @Autowired private ApplicationArguments arguments; public static void main(String[] args) { SpringApplication.run(ApplicationargumentsDemo2Application.class, args); } @RequestMapping("/") public String index() { return "key1=" + Arrays.toString(arguments.getOptionValues( "key1").toArray(new String[]{})) + "<br/>" + "key2=" + Arrays.toString(arguments.getOptionValues( "key2").toArray(new String[]{})); } }
启动应用程序后,使用浏览器访问 http://localhost:8080 ,效果如下图:
接下来,将介绍实现自己的 ApplicationRunner 类来获取参数。代码如下:
package com.huangx.springboot.applicationarguments_demo2; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; import java.util.Arrays; @Component public class MyApplicationRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { System.out.println("========= MyApplicationRunner ========="); for(String name : args.getOptionNames()) { System.out.println(name + "=" + Arrays.toString( args.getOptionValues(name).toArray(new String[]{}))); } } }
启动 Spring Boot 程序,输出结果如下:
========= MyApplicationRunner ========= key1=[val1] key2=[val2]
我们先从 SpringApplication.run() 方法开始查看,源代码如下:
源代码中,是直接 new 了一个 DefaultApplicationArguments 默认实现类作为 ApplicationArguments 的对象。继续点进去,查看 DefaultApplicationArguments 类的源代码,如下:
package org.springframework.boot; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.springframework.core.env.SimpleCommandLinePropertySource; import org.springframework.util.Assert; /** * Default implementation of {@link ApplicationArguments}. * * @author Phillip Webb * @since 1.4.1 */ public class DefaultApplicationArguments implements ApplicationArguments { private final Source source; private final String[] args; public DefaultApplicationArguments(String... args) { Assert.notNull(args, "Args must not be null"); this.source = new Source(args); this.args = args; } @Override public String[] getSourceArgs() { return this.args; } // 获取所有选项名集合 @Override public Set<String> getOptionNames() { String[] names = this.source.getPropertyNames(); return Collections.unmodifiableSet(new HashSet<>(Arrays.asList(names))); } // 判断给定的选项是否存在 @Override public boolean containsOption(String name) { return this.source.containsProperty(name); } // 获取指定key的选项值列表 @Override public List<String> getOptionValues(String name) { List<String> values = this.source.getOptionValues(name); return (values != null) ? Collections.unmodifiableList(values) : null; } // 返回在命令行上指定的非选项参数的列表。 @Override public List<String> getNonOptionArgs() { return this.source.getNonOptionArgs(); } private static class Source extends SimpleCommandLinePropertySource { Source(String[] args) { super(args); } @Override public List<String> getNonOptionArgs() { return super.getNonOptionArgs(); } @Override public List<String> getOptionValues(String name) { return super.getOptionValues(name); } } }
假如我们启动 Spring Boot 程序传递的参数为 “--key1=val1 --key2=val2 hello world”,则:
getOptionNames() 返回的 key1 和 key2
getOptionValues(String name) 如果你传递 key1 作为name,那么将返回仅包含 val1 的 List
getNonOptionArgs() 返回包含了 hello 和 world 字符串的 List
我们关注的重点应该是 Source 内部类,该类继承了 SimpleCommandLinePropertySource 类,而 SimpleCommandLinePropertySource 类继承了 CommandLinePropertySource 类。