首页 > 编程语言 >[spring-boot] 源码解读#org.springframework.boot.ApplicationArguments [转发]

[spring-boot] 源码解读#org.springframework.boot.ApplicationArguments [转发]

时间:2023-06-09 12:13:28浏览次数:58  
标签:选项 String -- spring boot 源码 参数 foo public

1 ApplicationArguments 概述

1.1 简述

  • org.springframework.boot.ApplicationArguments接口提供对用于运行org.springframework.boot.SpringApplication的参数访问。
  • ApplicationArguments 接口只有一个实现类DefaultApplicationArguments

1.2 使用示例

  • 示例1
@SpringBootApplication
public class QuartzBootStrap {
    public static void main(String[] args) {
        SpringApplication.run(QuartzBootStrap.class, args);
    }
}
  • 示例2 : 实现 ApplicationRunner 重新run方法
package com.ratel.mongo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.util.Set;

@Component
@Slf4j
public class ApplicationRunnerImpl implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        Set<String> optionNames = args.getOptionNames();
        for (String optionName : optionNames) {
            log.info("这是传过来的参数[{}]", optionName);
        }
        String[] sourceArgs = args.getSourceArgs();
        for (String sourceArg : sourceArgs) {
            log.info("这是传过来sourceArgs[{}]", sourceArg);
        }
    }
}
  • 示例3
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.DefaultApplicationArguments;
// ...

public class MySystemPropertiesTool {
    public SystemPropertiesTool(ApplicationArguments applicationArguments){
        this.applicationArguments = applicationArguments;
		
		List<String> optionArgs = applicationArguments.getOptionValues(variableName);// args = { "--foo="bar then baz" } , variableName = "foo" => optionArgs = {"bar then baz"}
		this.optionArgs = optionArgs;

		List<String> allNonOptionArgs = applicationArguments.getNonOptionArgs();// { "server.port=8089" , "server.port=8090", "boo=bar,then,baz" , "foo=bar then baz" }
		this.allNonOptionArgs = allNonOptionArgs;
		
		//...
	}
	
    public static void main(String[] args) {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		MySystemPropertiesTool systemPropertiesUtil = new MySystemPropertiesTool(applicationArguments);
		//...
	}
}

2 源码分析

2.1 ApplicationArguments 接口

public interface ApplicationArguments {

	/**
	 * 返回传递给应用程序的原始未处理参数
	 */
	String[] getSourceArgs();

	/**
	 * 返回所有选项参数的名称,例如,如果参数是"--foo=bar --debug"将会返回["foo", "debug"]
	 * @return the option names or an empty set
	 */
	Set<String> getOptionNames();

	/**
	 * 返回解析后的选项参数集合中是否包含给定名称的选项
	 * @param name the name to check
	 * @return {@code true} if the arguments contain an option with the given name
	 */
	boolean containsOption(String name);

	/**
	 * 返回与具有给定名称的arguments选项关联的值的集合
	 * 如果该选项存在并且没有参数值(例如:”--foo“),则返回一个空集合
	 * 如果该选项存在并且只有一个值 (例如: "--foo=bar"), 则返回一个包含一个元素的集合["bar"]
	 * 如果该选项存在并且有多个值(例如:"--foo=bar --foo=baz"),则返回一个包含每个值元素的集合["bar", "baz"]
	 * 如果选项不存在,则返回null
	 * @param name 选项名称
	 * @return 返回选项值的集合(不存在返回null)
	 */
	List<String> getOptionValues(String name);

	/**
	 * 返回已解析的非选项参数,不存在返回空集合
	 * @return the non-option arguments or an empty list
	 */
	List<String> getNonOptionArgs();

}

看过上面的源码,可能会有一个疑问,什么是选项参数?什么是非选项参数?这个选项参数留到后面在解答。

2.2 DefaultApplicationArguments 类 : ApplicationArguments接口唯一实现类

public class DefaultApplicationArguments implements ApplicationArguments {
	//内部类,获取参数的主要操作都在此类中
	private final Source source;
	//应用程序原始未处理的参数
	private final String[] args;
	//构造函数,args不可以为null
	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);
	}
	//获取所有解析后的选项参数值
	@Override
	public List<String> getOptionValues(String name) {
		List<String> values = this.source.getOptionValues(name);
		return (values != null) ? Collections.unmodifiableList(values) : null;
	}
	//获取所有非选项参数集合,如:[ "foo=bar", "foo=baz", "foo1=biz" ]
	@Override
	public List<String> getNonOptionArgs() {
		return this.source.getNonOptionArgs();
	}
	//内部类,继承了SimpleCommandLinePropertySource对命令行参数进行操作
	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);
		}
	}
}

2.3 SimpleCommandLinePropertySource 类

  • 与所有的CommandLinePropertySource实现一样,命令行参数分为两个不同的组(其另外一个实现JOptCommandLinePropertySource是使用第三方实现https://github.com/jopt-simple/jopt-simple):
  • 选项参数
  • 非选项参数
  • 使用选项参数必须遵循精确的语法,也就是说,选项必须以”--“为前缀,并且可以指定值,也可以不指定值;如果指定了一个值,则名称和值必须用”=“号分割,且不带空格,值可以是空字符串。

  • 选项参数的有效示例:

 --foo
 --foo=
 --foo=""
 --foo=bar
 --foo="bar then baz"
 --foo=bar,baz,biz
  • 选项参数的无效示例:
 -foo
 --foo bar
 --foo = bar
 --foo=bar --foo=baz --foo=biz
  • 非选项参数:
    在命令行中指定的没有”--“选项前缀的任何参数都将被视为非选项参数。
public class SimpleCommandLinePropertySource extends CommandLinePropertySource<CommandLineArgs> {

	/**
	 * 创建一个拥有默认名”commandLineArgs“和String[]参数的SimpleCommandLinePropertySource对象
	 */
	public SimpleCommandLinePropertySource(String... args) {
    //SimpleCommandLineArgsParser类用来解析命令行参数String[]数组,然后返回CommandLineArgs对象
		super(new SimpleCommandLineArgsParser().parse(args));
	}

	/**
	 * 创建一个指定name和String[]参数的SimpleCommandLinePropertySource对象
	 */
	public SimpleCommandLinePropertySource(String name, String[] args) {
		super(name, new SimpleCommandLineArgsParser().parse(args));
	}
	...

}

2.4 SimpleCommandLineArgsParser 解析类

使用选项参数必须遵循精确的语法,也就是说,选项必须以”–“为前缀,并且可以指定值,也可以不指定值;如果指定了一个值,则名称和值必须用”=“号分割,且不带空格,值可以是空字符串。

  • 选项参数的有效示例:
 --foo
 --foo=
 --foo=""
 --foo=bar
 --foo="bar then baz"
 --foo=bar,baz,biz
  • 选项参数的无效示例:
 -foo
 --foo bar
 --foo = bar
 --foo=bar --foo=baz --foo=biz
  • 非选项参数:

在命令行中指定的没有”--“选项前缀的任何参数都将被视为非选项参数。

class SimpleCommandLineArgsParser {

	/**
	 * 解析给定的String[]数组参数根据上面描述的规则,返回一个CommandLineArgs对象
	 * {@link CommandLineArgs} object.
	 * @param args command line arguments, typically from a {@code main()} method
	 */
	public CommandLineArgs parse(String... args) {
    //创建命令行参数对象
		CommandLineArgs commandLineArgs = new CommandLineArgs();
    //循环命令行参数
		for (String arg : args) {
      //如果是以”--“为前缀,则判定为选项参数
			if (arg.startsWith("--")) {
				String optionText = arg.substring(2);
				String optionName;
				String optionValue = null;
				int indexOfEqualsSign = optionText.indexOf('=');
				if (indexOfEqualsSign > -1) {
					optionName = optionText.substring(0, indexOfEqualsSign);
					optionValue = optionText.substring(indexOfEqualsSign + 1);
				}
				else {
					optionName = optionText;
				}
				if (optionName.isEmpty()) {
					throw new IllegalArgumentException("Invalid argument syntax: " + arg);
				}
        //新增选项参数
				commandLineArgs.addOptionArg(optionName, optionValue);
			}
			else {
         //新增非选项参数
				commandLineArgs.addNonOptionArg(arg);
			}
		}
		return commandLineArgs;
	}

}

2.5 org.springframework.core.env.CommandLineArgs 类

命令行参数的简单表示,分为”选项参数“和”非选项参数“;可以通过SimpleCommandLineArgsParser解析类解析得到。

class CommandLineArgs {
	//存放选项参数,参数名:参数值
	private final Map<String, List<String>> optionArgs = new HashMap<>();
  //存放非选项参数
	private final List<String> nonOptionArgs = new ArrayList<>();

	/**
	 * 添加给定的选项名和选项值
	 */
	public void addOptionArg(String optionName, @Nullable String optionValue) {
		if (!this.optionArgs.containsKey(optionName)) {
			this.optionArgs.put(optionName, new ArrayList<>());
		}
		if (optionValue != null) {
			this.optionArgs.get(optionName).add(optionValue);
		}
	}

	/**
	 * 返回命令行中所有选项参数的集合
	 */
	public Set<String> getOptionNames() {
		return Collections.unmodifiableSet(this.optionArgs.keySet());
	}

	/**
	 * 返回命令行中是否存在具有给定的选项名
	 */
	public boolean containsOption(String optionName) {
		return this.optionArgs.containsKey(optionName);
	}

	/**
	 * 返回与给定选项名关联的值列表,null表示该选项不存在,空列表表示没有值与该选项关联
	 */
	@Nullable
	public List<String> getOptionValues(String optionName) {
		return this.optionArgs.get(optionName);
	}

	/**
	 * 将给定的值添加到非选项列表
	 */
	public void addNonOptionArg(String value) {
		this.nonOptionArgs.add(value);
	}

	/**
	 * 返回在命令行上指定的非选项参数的列表
	 */
	public List<String> getNonOptionArgs() {
		return Collections.unmodifiableList(this.nonOptionArgs);
	}

}

X 参考文献

标签:选项,String,--,spring,boot,源码,参数,foo,public
From: https://www.cnblogs.com/johnnyzen/p/17468895.html

相关文章

  • 用Spring MVC实现用户登录的完整实例
    用SpringMVC实现用户登录的完整实例本例子是再Eclipse中建立一个Tomcat工程,来讲解SpringMVC的全过程,实例代码如下:<一>编写日记文件放在myMVC/WEB-INF/src下#指定日志输入文件的大小log4j.appender.stdout.MaxFileSize=500KBlog4j.appender.stdout.MaxBackupI......
  • 使用Spring方法注入协调不同步的bean
    使用Spring方法注入协调不同步的bean<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEbeansPUBLIC"-//SPRING//DTDBEAN//EN""http://www.springframework.org/dtd/spring-beans.dtd"><beans><bean......
  • 海外直播源码技术文字聊天功能的配置
    今天我要分享的知识和我们日常生活中常用到的一个东西有关,它就是文字。目前已知发现我国最早的文字是距今5000多年的甲骨文,随着历史的发展,文字也在不断的发展,一直发展到我们现在所使用的文字。网络时代的到来,让文字进入到了网络中,在网上我们可以用文字去写文章、搜索问题、聊天等,其......
  • SpringAOP
    一、proxy增强1、基于JDKjava自带的代理功能,只能针对接口,目标类与代理类为平级关系publicclassJDKProxy{ interfaceFoo{ voidfoo(); } staticclassTargetimplementsFoo{ publicvoidfoo(){ System.out.println("targetfoo"); } } publicstaticvo......
  • 深入浅出Spring原理及实战「缓存Cache开发系列」
    1.  缓存Cache的概念和作用在现代软件开发中,缓存已经成为了一个非常重要的概念。缓存是指将数据存储在一个临时的存储器中,以便于快速访问和读取。缓存的作用是提高系统的性能和响应速度,减少网络流量和数据库的负载。以电影院购票为例,当用户选择一部电影时,系统需要查询电影的......
  • 海外直播源码技术文字聊天功能的配置
     今天我要分享的知识和我们日常生活中常用到的一个东西有关,它就是文字。目前已知发现我国最早的文字是距今5000多年的甲骨文,随着历史的发展,文字也在不断的发展,一直发展到我们现在所使用的文字。网络时代的到来,让文字进入到了网络中,在网上我们可以用文字去写文章、搜索问题、聊天......
  • 美团太细了:Springcloud 微服务优雅停机,如何实现?
    文章很长,且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录博客园版为您奉上珍贵的学习资源:免费赠送:《尼恩Java面试宝典》持续更新+史上最全+面试必备2000页+面试必备+大厂必备+涨薪必备免费赠送:《尼恩技术圣经+高并发系列PDF》,帮你实现技术自由,完成职业升级,薪......
  • spring tx:advice 和 aop:config 配置事务
    <?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.or......
  • spring中获取属性的方法SpelExpressionParser()
    Aa=newA();Bb=newB();声明el表达式ExpressionParserpaeser=newSpelExpressionParser();设置你要通过el表达式取的字段Expressionaid=paeser.parseExpression("id");代表内置对象(b)中的id属性Expressionbid=paeser.parseExpression(b.id);如果b对象......
  • 50000多字,线程池源码详解!建议收藏
    你好,我是田哥。很多人对线程池总是一知半解,希望通过此文让你彻底的掌握线程池。不管是工作还是面试,这篇文章一定让你满载而归,学完这一篇,从此不再怕线程池。另外,除了能掌握线程池的技术以外,更多的是学会大佬们的设计思想。本文属于付费文,7个豆(1块钱),主要是文末有技术文档分享和技术分......