SpringBoot运行流程源码分析------阶段三(Spring Boot外化配置源码解析)

Spring Boot外化配置源码解析

外化配置简介

Spring Boot设计了非常特殊的加载指定属性文件(PropertySouce)的顺序,允许属性值合理的覆盖,属性值会以下面的优先级进行配置。
  • home目录下的Devtool全局设置属性(~/.spring-boot-devtools.properties,条件是当devtools激活时)
  • @TestPropertySource注解的测试用例。
  • @SpringBootTest#properties注解的测试用例。
  • 命令行参数。
  • 来自SPRING_APPLICATION_JSON的属性(内嵌在环境变量或系统属性中的内联JSON)
  • ServletConfig初始化参数
  • ServletContext初始化参数
  • java:comp/env的JNDI属性
  • Java系统属性(System.getProperties())
  • 操作系统环境变量
  • RandomValuePropertySource,只包含random.*中的属性
  • jar包外的Profile_specific应用属性(application-{profile}.propertis和YAML变量)
  • jar包内的Profile_specific应用属性(application-{profile}.propertis和YAML变量)
  • jar包外的应用配置(application.properties和YAML变量)
  • jar包内的应用配置(application.properties和YAML变量)
  • @Configuration类上的@PropertySource注解
  • 默认属性(通过SpringApplication.setDefaultProperties指定)

在以上配置方式中,我们经常使用的包括:命令参数,属性文件,YAML文件等内容,以下将围绕他们的运行及相关代码进行讲解。

ApplicationArguments参数处理

ApplicationArguments提供了针对参数的解析和查询功能。在Spring Boot运行阶段的章节中我们提到过,通过SpringApplication.run(args)传递的参数会被封装在ApplicationArguments接口中。本节我们来详细了解下ApplicationArguments接口。
接口定义及初始化

首先看一下ApplicationArguments接口的具体方法定义及功能介绍。

package org.springframework.boot;

import java.util.List;
import java.util.Set;
 
public interface ApplicationArguments {
   
	//返回原始未处理的参数(通过application传入的)
	String[] getSourceArgs();
	//返回所有参数的集合,如参数为:--foo=bar --debug,则返回【"foo","debug"】
	Set<String> getOptionNames();
	//选项参数中是否包含指定名称的参数
	boolean containsOption(String name);
	//根据选项参数的名称获取选项参数的值列表
	List<String> getOptionValues(String name);
	//返回非选项参数列表
	List<String> getNonOptionArgs();

}

通过接口定义可以看出,ApplicationArguments主要提供了针对参数名称和值的查询,以及判断是否存在指定参数的功能。

在Spring Boot的初始化运行过程中,ApplicationArguments接口的实例化操作默认是通过实现类DefaultApplicationArguments来完成的。DefaultApplicationArguments的底层又是基于Spring框架中的命令行配置源SimpleCommandLinePropertySource实现的,SpringCommandLinePropertySource是PropertySource抽象类的派生类。

以下代码中内部类Source便是SimppleCommandLinePropertySource的子类。

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;
	}
	......

	private static class Source extends SimpleCommandLinePropertySource {
   

		......

	}

}

我们再来看SimpleCommandLinePropertySource的构造方法,通过代码会发现默认使用spring的SimpleCommandLineArgsParser对args参加进行解析。

public class SimpleCommandLinePropertySource extends CommandLinePropertySource<CommandLineArgs> {
   
    public SimpleCommandLinePropertySource(String... args) {
   
        super((new SimpleCommandLineArgsParser()).parse(args));
    }
	//重载的构造方法
    public SimpleCommandLinePropertySource(String name, String[] args) {
   
        super(name, (new SimpleCommandLineArgsParser()).parse(args));
    }
    ......
}

除了构造方法之外,SimpleCommandLinePropertySource还提供了不同类型参数信息的获取和检查是否存在的功能,代码如下:

public class SimpleCommandLinePropertySource extends CommandLinePropertySource<CommandLineArgs> {
   
    ......
    //获取选项参数数组    
    public String[] getPropertyNames() {
   
        return StringUtils.toStringArray(((CommandLineArgs)this.source).getOptionNames());
    }
	//获取是否包含指定name的参数
    protected boolean containsOption(String name) {
   
        return ((CommandLineArgs)this.source).containsOption(name);
    }
	//获取指定name的选项参数列表
    @Nullable
    protected List<String> getOptionValues(String name) {
   
        return ((CommandLineArgs)this.source).getOptionValues(name);
    }
	//获取非选项参数列表
    protected List<String> getNonOptionArgs() {
   
        return ((CommandLineArgs)this.source).getNonOptionArgs();
    }
}

ApplicatinArguments,或者更进一步说是SimpleCommandLinePropertySource对参数类型是有所区分的,即选项参数和非选项参数。

选项参数必须以“–”为前缀,参数值可为空,该参数可以通过Spring Boot属性处理后使用,比如在执行jar -jar命令时,添加选项参数“–app.name=spring boot start",在代码中可以通过注解@Value属性及其他方式获取到该参数的值。该参数可以通过逗号分隔多个参数值,或者多次使用同一个参数来包含多个参数的值。

非选项参数并不要求以“–”前缀开始,可自行定义。非选项参数可以直接在jar -jar命令中定义参数为“non-option"的参数值。

以上所说的选项参数和非选项参数的解析是在SimpleCommandLinePropertySource构造方法中调用SimpleCommandLineArgsParser中完成的,代码如下:

class SimpleCommandLineArgsParser {
   
    SimpleCommandLineArgsParser() {
   
    }
	//解析args参数,返回一个完整的CommandLineArgs对象
    public CommandLineArgs parse(String... args) {
   
        CommandLineArgs commandLineArgs = new CommandLineArgs();
        String[] var3 = args;
        int var4 = args.length;
		//遍历参数
        for(int var5 = 0; var5 < var4; ++var5) {
   
            String arg = var3[var5];
            //解析选项参数,以"--"开头
            if (arg.startsWith("--")) {
   
                String optionText = arg.substring(2, arg.length());
                String optionValue = null;
                String optionName;
                //判断是--foo=bar参数格式,还是-foo参数格式,并分别处理获取值
                if (optionText.contains("=")) {
   
                    optionName = optionText.substring(0, optionText.indexOf(61));
                    optionValue = optionText.substring(optionText.indexOf(61) + 1
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

double_lifly

点喜欢就是最好的打赏!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值