spring核心第1 章:environment

environment功能

功能说明

在environment存储者spring中所有的变量信息,包括系统变量、jvm变量、以及当前程序定义的变量。同时用户可以通过变量名字获取对应的变量值,同时支持:变量值类型转换、变量占位符的解析等功能。

使用实例


        final ConfigurableApplicationContext run = SpringApplication.run(Main.class, args);
        
        //在applicationContext中有environment我们可以通过它获取
        final ConfigurableEnvironment environment = run.getEnvironment();
        //获取普通的配置变量
        final String test = environment.getProperty("test");
        //获取同时,并转换为int类型
        final Integer number = environment.getProperty("number", Integer.class);
        //获取包含占位符的变量
        final String placeholderTest = environment.getProperty("placeholderTest${test}");
        //获取变量,当不存在时,使用默认值
        final String property = environment.getProperty("${default:test}");

environment源码解析

在StandardEnvironment类中继承关系入下图:
在这里插入图片描述

其中主要的接口和方法有

  • PropertyResolver
  • conversion

PropertyResolver 主要实现的是变量的获取以及对于占位符的解析

conversion 主要实现的是对于变量值类型的转换

下面详细结束这些接口与类

父类接口说明

PropertyResolver

这个是顶级接口,主要定义了getProperty等获取变量相关的方法,同时包含 resolvePlaceholders 解析占位符方法。

Environment

在 PropertyResolver 基础上添加了系统运行环境profile相关的接口定义,但当单独解析environmen时无法看出来其作用,故暂不解析。

ConfigurablePropertyResolver

在 PropertyResolver 基础上添加可配置项,属性转换器 convension、占位符的前缀、后缀等配置。

ConfigurableEnvironment

在 Environment 与 ConfigurablePropertyResolver 基础上添加对环境的设置。暂不解析。

父类class说明

AbstractEnvironment

在当前类中,实现了所有的基本方法。除了 环境相关内容。其他都通过 PropertySourcesPropertyResolver来实现。具体解析见下文

StandardEnvironment

在父类的基础上添加系统变量、jvm变量 systemEnvironment sytemProperties。

MutablePropertySources

MutablePropertySources 是PropertySources的子类,在创建PropertySourcesPropertyResolver 对象时需要一个PropertySources对象作为参数。

我们可以看到 MutablePropertySources 就是一个存放批量PropertySource的集合,并且get、add、remove 等相应的方法。

对于 PropertySource 则是存放一个来源的配置。如jvm变量会存放在一个PropertySource 中,而系统变量会全部存在在另一个PropertySource 中,我们平时一个配置文件就是一个PropertySources对象。

至此我们可以看到 在Evironment中。我们所有的配置变量其实都保存在一个y又一个的PropertySource。而所有的 PropertySource又通过list被存放在MutablePropertySources 对象中。

PropertySourcesPropertyResolver

我们可以看到在其构造函数中需要一个PropertySources对象,而在AbstractEnvironment中是new出MutablePropertySources传进来的。根据之前的接口分析。其主要方法有getProperty和resolvePlaceholders两个方法接下来详细解析:

getProperty
    
    //所有的getProperty方法最终都会调用这个方法
    //key 变量名称,targetValueType 变量类型,resolveNestedPlaceholders 是否解析占位符
	@Nullable
	protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
		if (this.propertySources != null) {
		    //循环遍历MutablePropertySources中的每个propertySource对象,逐一通过get方法获取变量值。
		    //这也说明MutablePropertySources中排在前面的变量,有着更高的优先度。
			for (PropertySource<?> propertySource : this.propertySources) {
				if (logger.isTraceEnabled()) {
					logger.trace("Searching for key '" + key + "' in PropertySource '" +
							propertySource.getName() + "'");
				}
				Object value = propertySource.getProperty(key);
				if (value != null) {
				    //当resolveNestedPlaceholders 为true时,解析占位符。
					if (resolveNestedPlaceholders && value instanceof String) {
						value = resolveNestedPlaceholders((String) value);
					}
					logKeyFound(key, propertySource, value);
					//如果有必要,转换类型。
					return convertValueIfNecessary(value, targetValueType);
				}
			}
		}
		if (logger.isTraceEnabled()) {
			logger.trace("Could not find key '" + key + "' in any property source");
		}
		return null;
	}

在上面的代码中我们可以看到,其实属性的获取,就是去遍历propertySources中的每个propertySource尝试获取值。而对于占位符和类型转换,分别交给了resolveNestedPlaceholders和convertValueIfNecessary 方法

	@Nullable
	private PropertyPlaceholderHelper nonStrictHelper;

	@Nullable
	private PropertyPlaceholderHelper strictHelper;
	
	
	protected String resolveNestedPlaceholders(String value) {
		if (value.isEmpty()) {
			return value;
		}
		return (this.ignoreUnresolvableNestedPlaceholders ?
				resolvePlaceholders(value) : resolveRequiredPlaceholders(value));
	}
		@Override
	public String resolvePlaceholders(String text) {
		if (this.nonStrictHelper == null) {
			this.nonStrictHelper = createPlaceholderHelper(true);
		}
		return doResolvePlaceholders(text, this.nonStrictHelper);
	}

	@Override
	public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
		if (this.strictHelper == null) {
			this.strictHelper = createPlaceholderHelper(false);
		}
		return doResolvePlaceholders(text, this.strictHelper);
	}
	private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
		return helper.replacePlaceholders(text, this::getPropertyAsRawString);
	}

对于占位符的解析我们可以看到最终是委托给了PropertyPlaceholderHelper对象。但在PropertyPlaceholderHelper 中没有获取属性的功能。所有需要通过参数传入getPropertyAsRawString方法获取属性。具体方法见下一节。

	@Nullable
	protected <T> T convertValueIfNecessary(Object value, @Nullable Class<T> targetType) {
		if (targetType == null) {
			return (T) value;
		}
		ConversionService conversionServiceToUse = this.conversionService;
		if (conversionServiceToUse == null) {
			// Avoid initialization of shared DefaultConversionService if
			// no standard type conversion is needed in the first place...
			if (ClassUtils.isAssignableValue(targetType, value)) {
				return (T) value;
			}
			conversionServiceToUse = DefaultConversionService.getSharedInstance();
		}
		return conversionServiceToUse.convert(value, targetType);
	}

对于属性类型的转换是交给了DefaultConversionService 来做。我们将单独解析这个类。

resolvePlaceholders

	@Override
	public String resolvePlaceholders(String text) {
		if (this.nonStrictHelper == null) {
			this.nonStrictHelper = createPlaceholderHelper(true);
		}
		return doResolvePlaceholders(text, this.nonStrictHelper);
	}

PropertyPlaceholderHelper

在上文中。我们看到对于占位符的解析时通过这个类来进行的,我们将解析他的主要方法parseStringValue

//可能包含占位符的字符串,
//placeholderResolver通过key获取属性值,该方法不提供占位符解析
//visitedPlaceholders 递归记录以及便利过的属性
protected String parseStringValue(
			String value, PlaceholderResolver placeholderResolver, @Nullable Set<String> visitedPlaceholders) {

        //判断是否包含占位符
		int startIndex = value.indexOf(this.placeholderPrefix);
		if (startIndex == -1) {
			return value;
		}

		StringBuilder result = new StringBuilder(value);
		while (startIndex != -1) {
		    //找到对应的结束标记,这个方法考虑的嵌套情况
			int endIndex = findPlaceholderEndIndex(result, startIndex);
			if (endIndex != -1) {
			    //攫取当前字符串
				String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
				String originalPlaceholder = placeholder;
				if (visitedPlaceholders == null) {
					visitedPlaceholders = new HashSet<>(4);
				}
				//判断visitedPlaceholders中是否已经包含当前值,如果有说明以及循环依赖。
				if (!visitedPlaceholders.add(originalPlaceholder)) {
					throw new IllegalArgumentException(
							"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
				}
				// 递归调用,确保先解析当前字符串中的占位符
				placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
				// 已解析后的key获取值
				String propVal = placeholderResolver.resolvePlaceholder(placeholder);
				//当为空时,以valueSeparator判断是否有默认值
				if (propVal == null && this.valueSeparator != null) {
					int separatorIndex = placeholder.indexOf(this.valueSeparator);
					if (separatorIndex != -1) {
						String actualPlaceholder = placeholder.substring(0, separatorIndex);
						String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
						propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
						if (propVal == null) {
							propVal = defaultValue;
						}
					}
				}
				//再次尝试获取值,因为前文中默认值也可能包含占位符
				if (propVal != null) {
					// Recursive invocation, parsing placeholders contained in the
					// previously resolved placeholder value.
					propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
					result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
					if (logger.isTraceEnabled()) {
						logger.trace("Resolved placeholder '" + placeholder + "'");
					}
					startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
				}
				else if (this.ignoreUnresolvablePlaceholders) {
					// Proceed with unprocessed value.
					startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
				}
				else {
					throw new IllegalArgumentException("Could not resolve placeholder '" +
							placeholder + "'" + " in value \"" + value + "\"");
				}
				visitedPlaceholders.remove(originalPlaceholder);
			}
			else {
				startIndex = -1;
			}
		}
		return result.toString();
	}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值