版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/andy_zhang2007/article/details/84452581
概述
Spring框架将某个属性源抽象成了类PropertySource
,又将多个属性源PropertySource
抽象为接口PropertySources
。对某个PropertySource
对象中属性的解析,抽象成了接口PropertyResolver
,而类PropertySourcesPropertyResolver
则是Spring用于解析一个PropertySources
对象中属性的工具类。Spring应用Environment
对象中对其PropertySources
对象的属性解析,就是通过这样一个对象。
// Spring Environment 实现类的抽象基类 AbstractEnvironment代码片段
private final ConfigurablePropertyResolver propertyResolver =
new PropertySourcesPropertyResolver(this.propertySources);
源码解析
package org.springframework.core.env;
import org.springframework.lang.Nullable;
/**
* PropertyResolver implementation that resolves property values against
* an underlying set of PropertySources.
* 一个PropertyResolver实现类,用于解析一个PropertySources对象中的属性源集合中的属性。
*
* 这里PropertySourcesPropertyResolver继承自基类AbstractPropertyResolver,
* AbstractPropertyResolver提供了很多方法实现,不过这里不做过多解析,而仅仅关注
* 如何获取一个属性的值的逻辑。
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
* @see PropertySource
* @see PropertySources
* @see AbstractEnvironment
*/
public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
// PropertySources形式存在的属性源集合,该工具的工作对象
@Nullable
private final PropertySources propertySources;
/**
* Create a new resolver against the given property sources.
* @param propertySources the set of PropertySource objects to use
*/
public PropertySourcesPropertyResolver(@Nullable PropertySources propertySources) {
this.propertySources = propertySources;
}
// 查看是否包含某个指定名称的属性,判断方法:
// 1. 底层任何一个属性源包含该属性的话就认为是包含;
// 2. 否则认为是不包含。
@Override
public boolean containsProperty(String key) {
if (this.propertySources != null) {
for (PropertySource<?> propertySource : this.propertySources) {
if (propertySource.containsProperty(key)) {
return true;
}
}
}
return false;
}
// 获取某个指定名称的属性的值,如果该属性不被包含的话,返回null
// 不管该属性的值是什么类型,将它转换成字符串类型
@Override
@Nullable
public String getProperty(String key) {
return getProperty(key, String.class, true);
}
// 获取某个指定名称的属性的值,并将其转换成指定的类型,如果该属性不被包含的话,返回null
@Override
@Nullable
public <T> T getProperty(String key, Class<T> targetValueType) {
return getProperty(key, targetValueType, true);
}
// 获取某个指定名称的属性的值,如果该属性不被包含的话,返回null
// 不管该属性的值是什么类型,将它转换成字符串类型
@Override
@Nullable
protected String getPropertyAsRawString(String key) {
return getProperty(key, String.class, false);
}
// 获取某个指定名称的属性的值,并将其转换成指定的类型,如果该属性不被包含的话,返回null
// resolveNestedPlaceholders参数指示是否要解析属性值中包含的占位符
@Nullable
protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
if (this.propertySources != null) {
// 遍历每个属性源,如果发现目标属性被某个属性源包含,则获取它的值并按要求做相应的处理然后返回处理
// 后的值从这里使用for循环的方式来看,可以将属性源看作是一个List,索引较小的属性源先被访问,也就
// 是说,索引较小的属性源具有较高优先级
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) {
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");
}
// 任何属性源中都不包含该属性,返回null
return null;
}
/**
* Log the given key as found in the given PropertySource, resulting in
* the given value.
* The default implementation writes a debug log message with key and source.
* As of 4.3.3, this does not log the value anymore in order to avoid accidental
* logging of sensitive settings. Subclasses may override this method to change
* the log level and/or log message, including the property's value if desired.
* @param key the key found
* @param propertySource the PropertySource that the key has been found in
* @param value the corresponding value
* @since 4.3.1
*/
protected void logKeyFound(String key, PropertySource<?> propertySource, Object value) {
if (logger.isDebugEnabled()) {
logger.debug("Found key '" + key + "' in PropertySource '" + propertySource.getName() +
"' with value of type " + value.getClass().getSimpleName());
}
}
}