先说一下底层属性源的基本概念: 就像数据库底层可以是连接mysql,也可以是orcale,还可以是nosql数据库,例如: redis,这里也是同样的,属性可以来自配置文件,jdk环境变量和系统属性,还可以来自其他自定义的属性源,但是正如jdbc规定了统一访问数据库的接口一样,spring也是通过PropertyResolver统一规定了访问属性源里面属性的统一接口而已
/**
屏蔽不同底层属性源的获取属性接口的不同
*/
public interface PropertyResolver {
/**
返回给定的属性键是否可用于解析
*/
boolean containsProperty(String key);
/**
返回与给定键关联的属性值,如果无法解析键,则返回 null。
*/
@Nullable
String getProperty(String key);
/**
返回与给定键关联的属性值,如果无法解析键,则返回 defaultValue。
*/
String getProperty(String key, String defaultValue);
/**
返回与给定键关联的属性值,如果无法解析键,则返回 null。
targetType:属性值的预期类型
*/
@Nullable
<T> T getProperty(String key, Class<T> targetType);
/**
返回key关联的value,如果key解析不了,抛出异常
*/
String getRequiredProperty(String key) throws IllegalStateException;
<T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException;
///
/**
解析给定文本中的 {...} 占位符,用 getProperty 解析的相应属性值替换它们。
没有默认值的不可解析占位符将被忽略并保持不变。
*/
String resolvePlaceholders(String text);
/**
解析给定文本中的 {...} 占位符,用 getProperty 解析的相应属性值替换它们。没有默认值的不可解析占位符将导致抛出 IllegalArgumentException
*/
String resolveRequiredPlaceholders(String text) throws IllegalArgumentException;
}
PropertyResolver顶层接口规定了获取属性和解析占位符的相关方法,基本都是只读方法,这也是spring的一贯作风,底层接口只规定只读方法
ConfigurablePropertyResolver继承了PropertyResolver,主要提供写的方法,在spring中,可写意味着可配置,因此这些类通常以Configurable开头
/**
大多数(如果不是全部)PropertyResolver 类型都将实现的配置接口。
提供用于访问和自定义将属性值从一种类型转换为另一种类型时使用的 ConversionService 的工具。
*/
public interface ConfigurablePropertyResolver extends PropertyResolver {
/**
ConversionService主要用户属性的类型转换---一会我们会分析一下这个类
*/
ConfigurableConversionService getConversionService();
/**
注意:作为完全替换 ConversionService 的替代方法,
请考虑通过深入了解 getConversionService() 并调用诸如 addConverter 之类的方法来添加或删除单个 Converter 实例。
See Also:
PropertyResolver.getProperty(String, Class),
getConversionService(),
org.springframework.core.convert.converter.ConverterRegistry.addConverter
*/
void setConversionService(ConfigurableConversionService conversionService);
//
/**
设置被此解析器替换的占位符必须以前缀开头。 ---> ${
*/
void setPlaceholderPrefix(String placeholderPrefix);
/**
后缀---> }
*/
void setPlaceholderSuffix(String placeholderSuffix);
/**
指定由此解析器替换的占位符与其关联的默认值之间的分隔字符,如果不应将此类特殊字符作为值分隔符处理,则为 null。
${port:8080}--->默认为: --->如果port对于的key解析不存在,则使用:后面的默认值
*/
void setValueSeparator(@Nullable String valueSeparator);
/**
如果占位符解析不了,是否要忽略,true,原样保留,false,抛出异常
*/
void setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders);
/**
哪些属性必须存在,不然死啦啦滴干活
*/
void setRequiredProperties(String... requiredProperties);
/**
验证 setRequiredProperties 指定的每个属性是否存在并解析为非空值。
*/
void validateRequiredProperties() throws MissingRequiredPropertiesException;
}
基本上在PropertyResolver 获取属性的基础上,增加了属性转换器接口的规定和一下解析器接口相关配置的规定
/**
用于针对任何底层属性源解析属性的抽象基类。
*/
public abstract class AbstractPropertyResolver implements ConfigurablePropertyResolver {
protected final Log logger = LogFactory.getLog(getClass());
//转换器
@Nullable
private volatile ConfigurableConversionService conversionService;
//专门负责解析占位符的工具类---非严格模式---自动忽悠不存在的占位符属性解析
@Nullable
private PropertyPlaceholderHelper nonStrictHelper;
//和上面一样,但是是严格模式---如果占位符解析失败,会抛出异常
@Nullable
private PropertyPlaceholderHelper strictHelper;
//是否忽悠不可解析的占位符---默认是不忽悠,即抛出异常
private boolean ignoreUnresolvableNestedPlaceholders = false;
//占位符前缀-->默认是${
private String placeholderPrefix = SystemPropertyUtils.PLACEHOLDER_PREFIX;
//占位符后缀--->默认是}
private String placeholderSuffix = SystemPropertyUtils.PLACEHOLDER_SUFFIX;
//${port:8080}--->分割key和默认值的分隔符-->默认是:
@Nullable
private String valueSeparator = SystemPropertyUtils.VALUE_SEPARATOR;
//必须存在的属性---这些属性需要被校验
private final Set<String> requiredProperties = new LinkedHashSet<>();
//尝试获取一个属性转换器,如果不存在就利用双重锁来避免重复创建
@Override
public ConfigurableConversionService getConversionService() {
ConfigurableConversionService cs = this.conversionService;
if (cs == null) {
synchronized (this) {
cs = this.conversionService;
if (cs == null) {
//默认的转换器
cs = new DefaultConversionService();
this.conversionService = cs;
}
}
}
return cs;
}
//设置转换器---建议不要,一会我们对ConversionService进行分析的时候,大家就懂了
@Override
public void setConversionService(ConfigurableConversionService conversionService) {
Assert.notNull(conversionService, "ConversionService must not be null");
this.conversionService = conversionService;
}
@Override
public void setPlaceholderPrefix(String placeholderPrefix) {
Assert.notNull(placeholderPrefix, "'placeholderPrefix' must not be null");
this.placeholderPrefix = placeholderPrefix;
}
@Override
public void setPlaceholderSuffix(String placeholderSuffix) {
Assert.notNull(placeholderSuffix, "'placeholderSuffix' must not be null");
this.placeholderSuffix = placeholderSuffix;
}
@Override
public void setValueSeparator(@Nullable String valueSeparator) {
this.valueSeparator = valueSeparator;
}
@Override
public void setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders) {
this.ignoreUnresolvableNestedPlaceholders = ignoreUnresolvableNestedPlaceholders;
}
@Override
public void setRequiredProperties(String... requiredProperties) {
Collections.addAll(this.requiredProperties, requiredProperties);
}
//验证RequiredPropertie集合里面的属性是否都存在
@Override
public void validateRequiredProperties() {
MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
for (String key : this.requiredProperties) {
if (this.getProperty(key) == null) {
ex.addMissingRequiredProperty(key);
}
}
if (!ex.getMissingRequiredProperties().isEmpty()) {
throw ex;
}
}
@Override
public boolean containsProperty(String key) {
return (getProperty(key) != null);
}
@Override
@Nullable
public String getProperty(String key) {
return getProperty(key, String.class);
}
@Override
public String getProperty(String key, String defaultValue) {
String value = getProperty(key);
return (value != null ? value : defaultValue);
}
@Override
public <T> T getProperty(String key, Class<T> targetType, T defaultValue) {
T value = getProperty(key, targetType);
return (value != null ? value : defaultValue);
}
@Override
public String getRequiredProperty(String key) throws IllegalStateException {
String value = getProperty(key);
if (value == null) {
throw new IllegalStateException("Required key '" + key + "' not found");
}
return value;
}
@Override
public <T> T getRequiredProperty(String key, Class<T> valueType) throws IllegalStateException {
T value = getProperty(key, valueType);
if (value == null) {
throw new IllegalStateException("Required key '" + key + "' not found");
}
return 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);
}
/**
解析给定字符串中的占位符,根据 setIgnoreUnresolvableNestedPlaceholders
的值来确定任何不可解析的占位符是否应该引发异常或被忽略。
*/
protected String resolveNestedPlaceholders(String value) {
if (value.isEmpty()) {
return value;
}
return (this.ignoreUnresolvableNestedPlaceholders ?
resolvePlaceholders(value) : resolveRequiredPlaceholders(value));
}
//创建负责占位符解析的工具类
private PropertyPlaceholderHelper createPlaceholderHelper(boolean ignoreUnresolvablePlaceholders) {
return new PropertyPlaceholderHelper(this.placeholderPrefix, this.placeholderSuffix,
this.valueSeparator, ignoreUnresolvablePlaceholders);
}
//利用工具类解析占位符
private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
return helper.replacePlaceholders(text, this::getPropertyAsRawString);
}
/**
如有必要,将给定值转换为指定的目标类型。
*/
@SuppressWarnings("unchecked")
@Nullable
protected <T> T convertValueIfNecessary(Object value, @Nullable Class<T> targetType) {
if (targetType == null) {
return (T) value;
}
ConversionService conversionServiceToUse = this.conversionService;
if (conversionServiceToUse == null) {
//如果首先不需要标准类型转换,请避免初始化共享 DefaultConversionService...
if (ClassUtils.isAssignableValue(targetType, value)) {
return (T) value;
}
conversionServiceToUse = DefaultConversionService.getSharedInstance();
}
//进行类型转换
return conversionServiceToUse.convert(value, targetType);
}
/**
将指定的属性作为原始字符串检索,即不解析占位符
*/
@Nullable
protected abstract String getPropertyAsRawString(String key);
}
该类主要是对两个父接口的功能做出了具体的实现,但是因为底层数据源不同,因此具体的属性值获取功能还是要交给下面不同数据源的子类来完成
/**
根据一组基础 PropertySource(属性源集合) 解析属性值的 PropertyResolver 实现
*/
public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
//属性源集合
@Nullable
private final PropertySources propertySources;
/**
* 通过给定的一组属性源来创建属性解析器
*/
public PropertySourcesPropertyResolver(@Nullable PropertySources propertySources) {
this.propertySources = propertySources;
}
//遍历每个属性源,询问是否包含指定要查看的key
@Override
public boolean containsProperty(String key) {
if (this.propertySources != null) {
for (PropertySource<?> propertySource : this.propertySources) {
if (propertySource.containsProperty(key)) {
return true;
}
}
}
return false;
}
//getProperty默认都会去解析占位符的
@Override
@Nullable
public String getProperty(String key) {
return getProperty(key, String.class, true);
}
@Override
@Nullable
public <T> T getProperty(String key, Class<T> targetValueType) {
return getProperty(key, targetValueType, true);
}
//该方法不会去解析占位符
@Override
@Nullable
protected String getPropertyAsRawString(String key) {
//不去解析占位符
return getProperty(key, String.class, false);
}
//属性key,返回value类型,是否解析占位符
//该方法还可以看出一点,就是数据源在集合中位置的先后问题,因为是轮询遍历,只要找到一个符合的就直接返回,因此属性源的先后问题
//很重要,不注意的话,会产生属性覆盖的问题
@Nullable
protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
if (this.propertySources != null) {
//依旧是遍历每个数据源
for (PropertySource<?> propertySource : this.propertySources) {
if (logger.isTraceEnabled()) {
logger.trace("Searching for key '" + key + "' in PropertySource '" +
propertySource.getName() + "'");
}
//尝试从每个数据源去寻找指定的key对应的value
Object value = propertySource.getProperty(key);
if (value != null) {
//如果对于value存在,并且value是string类型并且需要解析占位符
if (resolveNestedPlaceholders && value instanceof String) {
//解析value里面的占位符---如果存在的话
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;
}
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());
}
}
}
因为抽象类实现了大部分的功能,但是对于属性的获取却没有具体实现,是因为属性的获取会根据数据源的不同而发生变化,因此需要子类实现
public interface ConversionService {
/**
如果 sourceType 的对象可以转换为 targetType,则返回 true。如果此方法返回 true,
则表示 convert(Object, Class) 能够将 sourceType 的实例转换为 targetType。
关于集合、数组和映射类型的特别说明:
对于集合、数组和映射类型之间的转换,如果基础元素不可转换,
即使转换调用仍可能生成 ConversionException,此方法也将返回 true。
在使用集合和地图时,调用者应该处理这种特殊情况。
*/
boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType);
/**
和上面一样,只不过用类型描述符来封装了类型相关的上下文信息
*/
boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType);
/**
将目标对象转换为指定类型
*/
@Nullable
<T> T convert(@Nullable Object source, Class<T> targetType);
/**
还是提供一个待转换的目标对象,和目标对象类型描述符号,还有转换后对象的类型描述符
*/
@Nullable
Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);
}
public interface ConverterRegistry {
/**
添加一个转换器,Converter<S, T>: S是源类型,T是目标类型
*/
void addConverter(Converter<?, ?> converter);
/**
指明了源类型和目标类型
*/
<S, T> void addConverter(Class<S> sourceType, Class<T> targetType, Converter<? super S, ? extends T> converter);
/**
添加一个通用转换器
*/
void addConverter(GenericConverter converter);
/**
* 添加一个转换器工厂
*/
void addConverterFactory(ConverterFactory<?, ?> factory);
/**
移除指定转换器,该转换器负责将sourceType类型的源对象转换为targetType类型的目标对象
*/
void removeConvertible(Class<?> sourceType, Class<?> targetType);
}
ConverterRegistry主要负责管理转换器的添加和移除
/**
集成了转换的功能和对转换器管理的功能
*/
public interface ConfigurableConversionService extends ConversionService, ConverterRegistry {
}
该类代码比较多,希望大家做好准备
public class GenericConversionService implements ConfigurableConversionService {
/**
* 当类型转换不需要的时候,会使用该转换器
*/
private static final GenericConverter NO_OP_CONVERTER = new NoOpConverter("NO_OP");
/**
* 当没有合适的转换器时,会返回下面这个转换器,表示无匹配
*/
private static final GenericConverter NO_MATCH = new NoOpConverter("NO_MATCH");
//管理向服务注册的所有转换器。
private final Converters converters = new Converters();
//转换器缓存---ConverterCacheKey是以SourceType和TargetType组合起来作为key的
//value就是负责这个转换过程的转换器
private final Map<ConverterCacheKey, GenericConverter> converterCache = new ConcurrentReferenceHashMap<>(64);
// ConverterRegistry implementation
@Override
public void addConverter(Converter<?, ?> converter) {
//这里返回的typeInfo长度为2,一个封装了SourceType,另一个封装的是TargetType
ResolvableType[] typeInfo = getRequiredTypeInfo(converter.getClass(), Converter.class);
//这里会判断是否是被代理过的,如果是被代理过的,会先拿到转换器的真实类型
if (typeInfo == null && converter instanceof DecoratingProxy) {
typeInfo = getRequiredTypeInfo(((DecoratingProxy) converter).getDecoratedClass(), Converter.class);
}
if (typeInfo == null) {
throw new IllegalArgumentException("Unable to determine source type <S> and target type <T> for your " +
"Converter [" + converter.getClass().getName() + "]; does the class parameterize those types?");
}
//ConverterAdapter继承了ConditionalGenericConverter
//它内部拥有一个转换器对象,还有源类型,目标类型
addConverter(new ConverterAdapter(converter, typeInfo[0], typeInfo[1]));
}
@Override
public <S, T> void addConverter(Class<S> sourceType, Class<T> targetType, Converter<? super S, ? extends T> converter) {
addConverter(new ConverterAdapter(
converter, ResolvableType.forClass(sourceType), ResolvableType.forClass(targetType)));
}
@Override
public void addConverter(GenericConverter converter) {
//每次向注册表添加一个转换器,都需要清空一下转换器缓存
this.converters.add(converter);
invalidateCache();
}
//还可以通过工厂来暴露获得一个转换器
@Override
public void addConverterFactory(ConverterFactory<?, ?> factory) {
//和上面一样,ResolvableType还是两个,一个封装了SourceType,另一个封装的是TargetType
ResolvableType[] typeInfo = getRequiredTypeInfo(factory.getClass(), ConverterFactory.class);
//检查代理
if (typeInfo == null && factory instanceof DecoratingProxy) {
typeInfo = getRequiredTypeInfo(((DecoratingProxy) factory).getDecoratedClass(), ConverterFactory.class);
}
if (typeInfo == null) {
throw new IllegalArgumentException("Unable to determine source type <S> and target type <T> for your " +
"ConverterFactory [" + factory.getClass().getName() + "]; does the class parameterize those types?");
}
//ConverterFactoryAdapter也继承了ConditionalGenericConverter,下面有该内部类的源码
addConverter(new ConverterFactoryAdapter(factory,
new ConvertiblePair(typeInfo[0].toClass(), typeInfo[1].toClass())));
}
//移除一个转换器
@Override
public void removeConvertible(Class<?> sourceType, Class<?> targetType) {
this.converters.remove(sourceType, targetType);
invalidateCache();
}
// ConversionService implementation
@Override
public boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType) {
Assert.notNull(targetType, "Target type to convert to cannot be null");
return canConvert((sourceType != null ? TypeDescriptor.valueOf(sourceType) : null),
TypeDescriptor.valueOf(targetType));
}
@Override
public boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
Assert.notNull(targetType, "Target type to convert to cannot be null");
if (sourceType == null) {
return true;
}
//能找到一个转换器就代表可以进行转换
GenericConverter converter = getConverter(sourceType, targetType);
return (converter != null);
}
/**
* 是否可以不用经过类型转换,例如sourceType是targetType的自实现类
*/
public boolean canBypassConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
Assert.notNull(targetType, "Target type to convert to cannot be null");
if (sourceType == null) {
return true;
}
//如果查到的转换器时NO_OP_CONVERTER,表明不需要进行类型转换,直接返回原对象即可
GenericConverter converter = getConverter(sourceType, targetType);
return (converter == NO_OP_CONVERTER);
}
@Override
@SuppressWarnings("unchecked")
@Nullable
public <T> T convert(@Nullable Object source, Class<T> targetType) {
Assert.notNull(targetType, "Target type to convert to cannot be null");
return (T) convert(source, TypeDescriptor.forObject(source), TypeDescriptor.valueOf(targetType));
}
//真正处理类型转换的类
@Override
@Nullable
public Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
Assert.notNull(targetType, "Target type to convert to cannot be null");
if (sourceType == null) {
Assert.isTrue(source == null, "Source must be [null] if source type == [null]");
//处理结果-----convertNullSource(null, targetType)会返回null
//除非targetType是Optional,会返回Optional.empty()
return handleResult(null, targetType, convertNullSource(null, targetType));
}
if (source != null && !sourceType.getObjectType().isInstance(source)) {
throw new IllegalArgumentException("Source to convert from must be an instance of [" +
sourceType + "]; instead it was a [" + source.getClass().getName() + "]");
}
//获取转换器
GenericConverter converter = getConverter(sourceType, targetType);
if (converter != null) {
//转换器进行类型转换---invokeConverter就是直接调用Convert的convert方法---不同Convert的convert方法实现不同
Object result = ConversionUtils.invokeConverter(converter, source, sourceType, targetType);
//处理结果
return handleResult(sourceType, targetType, result);
}
//处理结果---转换器没找到
return handleConverterNotFound(source, sourceType, targetType);
}
@Nullable
public Object convert(@Nullable Object source, TypeDescriptor targetType) {
return convert(source, TypeDescriptor.forObject(source), targetType);
}
@Override
public String toString() {
return this.converters.toString();
}
// Protected template methods
@Nullable
protected Object convertNullSource(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
//对Optional做特殊处理
if (targetType.getObjectType() == Optional.class) {
return Optional.empty();
}
return null;
}
@Nullable
protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
//ConverterCacheKey就是封装了sourceType和targetType
ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);
//然后用这个key先去缓存中寻找
GenericConverter converter = this.converterCache.get(key);
if (converter != null) {
//如果缓存中有直接返回,如果没有即转换器为NO_MATCH ,那么返回null
//可能直接因为尝试去寻找过了,发现没有对应的转换器,那么就会在缓存中标记一下
//当前这个转换组合没有对应的转换器
return (converter != NO_MATCH ? converter : null);
}
//缓存中没有,再尝试从注册表中去寻找对应的转换器
converter = this.converters.find(sourceType, targetType);
if (converter == null) {
//还是没有,就返回一个默认的转换器
//(sourceType.isAssignableTo(targetType) ? NO_OP_CONVERTER : null);
converter = getDefaultConverter(sourceType, targetType);
}
if (converter != null) {
//将找到的转换器缓存起来
this.converterCache.put(key, converter);
return converter;
}
//如果找不到,也做一个标记,不然每次都去查找一个不存在的转换器,这是最浪费时间的
this.converterCache.put(key, NO_MATCH);
return null;
}
@Nullable
protected GenericConverter getDefaultConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
return (sourceType.isAssignableTo(targetType) ? NO_OP_CONVERTER : null);
}
// Internal helpers
@Nullable
private ResolvableType[] getRequiredTypeInfo(Class<?> converterClass, Class<?> genericIfc) {
ResolvableType resolvableType = ResolvableType.forClass(converterClass).as(genericIfc);
ResolvableType[] generics = resolvableType.getGenerics();
if (generics.length < 2) {
return null;
}
//这个方法只需要知道返回的ResolvableType[] generics长度为2
//一个封装的是sourceType
//另一个是targetType
//resolve()返回的就是当前ResolvableType关联的对象的Class,目标对象的或者转换后对象的
Class<?> sourceType = generics[0].resolve();
Class<?> targetType = generics[1].resolve();
if (sourceType == null || targetType == null) {
return null;
}
return generics;
}
private void invalidateCache() {
this.converterCache.clear();
}
@Nullable
private Object handleConverterNotFound(
@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
assertNotPrimitiveTargetType(sourceType, targetType);
return null;
}
//如果转换关系直接存在继承关系,那么就不需要转换了,直接返回即可
if ((sourceType == null || sourceType.isAssignableTo(targetType)) &&
targetType.getObjectType().isInstance(source)) {
return source;
}
throw new ConverterNotFoundException(sourceType, targetType);
}
@Nullable
private Object handleResult(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType, @Nullable Object result) {
if (result == null) {
assertNotPrimitiveTargetType(sourceType, targetType);
}
return result;
}
private void assertNotPrimitiveTargetType(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
if (targetType.isPrimitive()) {
throw new ConversionFailedException(sourceType, targetType, null,
new IllegalArgumentException("A null value cannot be assigned to a primitive type"));
}
}
/**
* 转换器的适配器
*/
@SuppressWarnings("unchecked")
private final class ConverterAdapter implements ConditionalGenericConverter {
//封装一个传入的转换器
private final Converter<Object, Object> converter;
//ConvertiblePair负责封装TargetType和SourceType---GenericConverter接口里面的内部类
private final ConvertiblePair typeInfo;
//ResolvableType在这里只是为了保存最终要转换的对象的类型
private final ResolvableType targetType;
public ConverterAdapter(Converter<?, ?> converter, ResolvableType sourceType, ResolvableType targetType) {
this.converter = (Converter<Object, Object>) converter;
this.typeInfo = new ConvertiblePair(sourceType.toClass(), targetType.toClass());
this.targetType = targetType;
}
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(this.typeInfo);
}
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
// Check raw type first...
if (this.typeInfo.getTargetType() != targetType.getObjectType()) {
return false;
}
// Full check for complex generic type match required?
ResolvableType rt = targetType.getResolvableType();
if (!(rt.getType() instanceof Class) && !rt.isAssignableFrom(this.targetType) &&
!this.targetType.hasUnresolvableGenerics()) {
return false;
}
//如果保存的converter是ConditionalConverter,那么需要调用其matches来做判决
return !(this.converter instanceof ConditionalConverter) ||
((ConditionalConverter) this.converter).matches(sourceType, targetType);
}
@Override
@Nullable
public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return convertNullSource(sourceType, targetType);
}
return this.converter.convert(source);
}
@Override
public String toString() {
return (this.typeInfo + " : " + this.converter);
}
}
/**
* Adapts a {@link ConverterFactory} to a {@link GenericConverter}.
*/
@SuppressWarnings("unchecked")
private final class ConverterFactoryAdapter implements ConditionalGenericConverter {
private final ConverterFactory<Object, Object> converterFactory;
private final ConvertiblePair typeInfo;
public ConverterFactoryAdapter(ConverterFactory<?, ?> converterFactory, ConvertiblePair typeInfo) {
this.converterFactory = (ConverterFactory<Object, Object>) converterFactory;
this.typeInfo = typeInfo;
}
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(this.typeInfo);
}
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
boolean matches = true;
if (this.converterFactory instanceof ConditionalConverter) {
matches = ((ConditionalConverter) this.converterFactory).matches(sourceType, targetType);
}
if (matches) {
Converter<?, ?> converter = this.converterFactory.getConverter(targetType.getType());
if (converter instanceof ConditionalConverter) {
matches = ((ConditionalConverter) converter).matches(sourceType, targetType);
}
}
return matches;
}
@Override
@Nullable
public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return convertNullSource(sourceType, targetType);
}
return this.converterFactory.getConverter(targetType.getObjectType()).convert(source);
}
@Override
public String toString() {
return (this.typeInfo + " : " + this.converterFactory);
}
}
/**
* Key for use with the converter cache.
*/
private static final class ConverterCacheKey implements Comparable<ConverterCacheKey> {
private final TypeDescriptor sourceType;
private final TypeDescriptor targetType;
public ConverterCacheKey(TypeDescriptor sourceType, TypeDescriptor targetType) {
this.sourceType = sourceType;
this.targetType = targetType;
}
@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (!(other instanceof ConverterCacheKey)) {
return false;
}
ConverterCacheKey otherKey = (ConverterCacheKey) other;
//ConverterCacheKey重写了比较方法
return (this.sourceType.equals(otherKey.sourceType)) &&
this.targetType.equals(otherKey.targetType);
}
...
}
/**
* Manages all converters registered with the service.
* 管理所有转换器的注册表服务
*/
private static class Converters {
//全局转换器---存放ConditionalConverter
private final Set<GenericConverter> globalConverters = new CopyOnWriteArraySet<>();
//转换器注册表----存放GenericConverter
private final Map<ConvertiblePair, ConvertersForPair> converters = new ConcurrentHashMap<>(256);
public void add(GenericConverter converter) {
//获取当前converter可以转换的所有类型
Set<ConvertiblePair> convertibleTypes = converter.getConvertibleTypes();
//如果为空,说明可能是ConditionalConverter
if (convertibleTypes == null) {
Assert.state(converter instanceof ConditionalConverter,
"Only conditional converters may return null convertible types");
//存放在全局转换器集合中
this.globalConverters.add(converter);
}
else {
//一个转换器可以同时对多个类型转换进行处理
for (ConvertiblePair convertiblePair : convertibleTypes) {
//返回一个ConvertersForPair ,然后调用其add方法,让其包裹当前converter
getMatchableConverters(convertiblePair).add(converter);
}
}
}
private ConvertersForPair getMatchableConverters(ConvertiblePair convertiblePair) {
//ConvertersForPair包装了一个GenericConverter
return this.converters.computeIfAbsent(convertiblePair, k -> new ConvertersForPair());
}
public void remove(Class<?> sourceType, Class<?> targetType) {
this.converters.remove(new ConvertiblePair(sourceType, targetType));
}
/**
* Find a {@link GenericConverter} given a source and target type.
* <p>This method will attempt to match all possible converters by working
* through the class and interface hierarchy of the types.
* @param sourceType the source type
* @param targetType the target type
* @return a matching {@link GenericConverter}, or {@code null} if none found
*/
@Nullable
public GenericConverter find(TypeDescriptor sourceType, TypeDescriptor targetType) {
// Search the full type hierarchy
//hierarchy是继承的意思--对getClassHierarchy方法感兴趣的可以自行研究
List<Class<?>> sourceCandidates = getClassHierarchy(sourceType.getType());
List<Class<?>> targetCandidates = getClassHierarchy(targetType.getType());
//寻找适配的转换器---找到一个就直接返回
for (Class<?> sourceCandidate : sourceCandidates) {
for (Class<?> targetCandidate : targetCandidates) {
ConvertiblePair convertiblePair = new ConvertiblePair(sourceCandidate, targetCandidate);
//尝试获取已经注册在注册表中的一个转换器
GenericConverter converter = getRegisteredConverter(sourceType, targetType, convertiblePair);
if (converter != null) {
return converter;
}
}
}
return null;
}
@Nullable
private GenericConverter getRegisteredConverter(TypeDescriptor sourceType,
TypeDescriptor targetType, ConvertiblePair convertiblePair) {
// Check specifically registered converters
//先去注册表中找
ConvertersForPair convertersForPair = this.converters.get(convertiblePair);
if (convertersForPair != null) {
//注册表有就直接返回
GenericConverter converter = convertersForPair.getConverter(sourceType, targetType);
if (converter != null) {
return converter;
}
}
//没有再去全局适配器集合里面找
// Check ConditionalConverters for a dynamic match
for (GenericConverter globalConverter : this.globalConverters) {
//全局适配器集合里面装的是ConditionalConverter类型的转换器,调用其match方法进行匹配
if (((ConditionalConverter) globalConverter).matches(sourceType, targetType)) {
return globalConverter;
}
}
return null;
}
/**
* Returns an ordered class hierarchy for the given type.
* @param type the type
* @return an ordered list of all classes that the given type extends or implements
*/
private List<Class<?>> getClassHierarchy(Class<?> type) {
List<Class<?>> hierarchy = new ArrayList<>(20);
Set<Class<?>> visited = new HashSet<>(20);
addToClassHierarchy(0, ClassUtils.resolvePrimitiveIfNecessary(type), false, hierarchy, visited);
boolean array = type.isArray();
int i = 0;
while (i < hierarchy.size()) {
Class<?> candidate = hierarchy.get(i);
candidate = (array ? candidate.getComponentType() : ClassUtils.resolvePrimitiveIfNecessary(candidate));
Class<?> superclass = candidate.getSuperclass();
if (superclass != null && superclass != Object.class && superclass != Enum.class) {
addToClassHierarchy(i + 1, candidate.getSuperclass(), array, hierarchy, visited);
}
addInterfacesToClassHierarchy(candidate, array, hierarchy, visited);
i++;
}
if (Enum.class.isAssignableFrom(type)) {
addToClassHierarchy(hierarchy.size(), Enum.class, array, hierarchy, visited);
addToClassHierarchy(hierarchy.size(), Enum.class, false, hierarchy, visited);
addInterfacesToClassHierarchy(Enum.class, array, hierarchy, visited);
}
addToClassHierarchy(hierarchy.size(), Object.class, array, hierarchy, visited);
addToClassHierarchy(hierarchy.size(), Object.class, false, hierarchy, visited);
return hierarchy;
}
private void addInterfacesToClassHierarchy(Class<?> type, boolean asArray,
List<Class<?>> hierarchy, Set<Class<?>> visited) {
for (Class<?> implementedInterface : type.getInterfaces()) {
addToClassHierarchy(hierarchy.size(), implementedInterface, asArray, hierarchy, visited);
}
}
private void addToClassHierarchy(int index, Class<?> type, boolean asArray,
List<Class<?>> hierarchy, Set<Class<?>> visited) {
if (asArray) {
type = Array.newInstance(type, 0).getClass();
}
if (visited.add(type)) {
hierarchy.add(index, type);
}
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("ConversionService converters =\n");
for (String converterString : getConverterStrings()) {
builder.append('\t').append(converterString).append('\n');
}
return builder.toString();
}
private List<String> getConverterStrings() {
List<String> converterStrings = new ArrayList<>();
for (ConvertersForPair convertersForPair : this.converters.values()) {
converterStrings.add(convertersForPair.toString());
}
Collections.sort(converterStrings);
return converterStrings;
}
}
/**
* Manages converters registered with a specific {@link ConvertiblePair}.
*/
private static class ConvertersForPair {
//一个转换器可以负责多个类型的转换工作,一个类型的转换工作也可以由多个转换器完成,这两者之间是多对多的关系
private final Deque<GenericConverter> converters = new ConcurrentLinkedDeque<>();
public void add(GenericConverter converter) {
this.converters.addFirst(converter);
}
@Nullable
public GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
for (GenericConverter converter : this.converters) {
//如果是ConditionalGenericConverter,还需判断match方法是否符合要求
if (!(converter instanceof ConditionalGenericConverter) ||
((ConditionalGenericConverter) converter).matches(sourceType, targetType)) {
return converter;
}
}
return null;
}
@Override
public String toString() {
return StringUtils.collectionToCommaDelimitedString(this.converters);
}
}
/**
* Internal converter that performs no operation.
*/
private static class NoOpConverter implements GenericConverter {
private final String name;
public NoOpConverter(String name) {
this.name = name;
}
@Override
@Nullable
public Set<ConvertiblePair> getConvertibleTypes() {
return null;
}
@Override
@Nullable
public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return source;
}
@Override
public String toString() {
return this.name;
}
}
}
/**
* <S> the source type
* <T> the target type
* 函数式接口,可以用lambda替换
*/
@FunctionalInterface
public interface Converter<S, T> {
/**
* 将S类型的目标对象,转换为T类型的对象返回
*/
@Nullable
T convert(S source);
/**
* 默认实现---再次将得到的Target对象,转换为U类型的对象
*/
default <U> Converter<S, U> andThen(Converter<? super T, ? extends U> after) {
Assert.notNull(after, "After Converter must not be null");
return (S s) -> {
//先将S类型的对象转换为T类型的对象
T initialResult = convert(s);
//转换结果不为NULL,那么再尝试将T类型的对象转换为U类型的对象
return (initialResult != null ? after.convert(initialResult) : null);
};
}
}
可以看到其子实现类众多
这里个人比较懒,就挑了一个最简单的来讲一下吧
final class StringToBooleanConverter implements Converter<String, Boolean> {
private static final Set<String> trueValues = new HashSet<>(8);
private static final Set<String> falseValues = new HashSet<>(8);
static {
trueValues.add("true");
trueValues.add("on");
trueValues.add("yes");
trueValues.add("1");
falseValues.add("false");
falseValues.add("off");
falseValues.add("no");
falseValues.add("0");
}
//拿到字符串,判断其在真值集合还是假值集合,然后分别处理返回即可
@Override
@Nullable
public Boolean convert(String source) {
String value = source.trim();
if (value.isEmpty()) {
return null;
}
value = value.toLowerCase();
if (trueValues.contains(value)) {
return Boolean.TRUE;
}
else if (falseValues.contains(value)) {
return Boolean.FALSE;
}
else {
throw new IllegalArgumentException("Invalid boolean value '" + source + "'");
}
}
}
/**
* 用于在两种或多种类型之间进行转换的通用转换器接口
*/
public interface GenericConverter {
/**
ConvertiblePair封装了源类型和目标类型
并且这里返回的是一个set集合,说明我们可以一次性对多个类型进行转换
*/
@Nullable
Set<ConvertiblePair> getConvertibleTypes();
/**
* 通过类型描述符来包装源类型和目标类型
*/
@Nullable
Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
/**
* Holder for a source-to-target class pair.
*/
final class ConvertiblePair {
private final Class<?> sourceType;
private final Class<?> targetType;
/**
* Create a new source-to-target pair.
* @param sourceType the source type
* @param targetType the target type
*/
public ConvertiblePair(Class<?> sourceType, Class<?> targetType) {
Assert.notNull(sourceType, "Source type must not be null");
Assert.notNull(targetType, "Target type must not be null");
this.sourceType = sourceType;
this.targetType = targetType;
}
public Class<?> getSourceType() {
return this.sourceType;
}
public Class<?> getTargetType() {
return this.targetType;
}
}
}
//s是源类型,R是转换后的类型
public interface ConverterFactory<S, R> {
/**
T是R或者R的子类
*/
<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}
spring中很多对象都不是直接new出来的,而是有一个工厂来生产这些对象的
/**
通常用于根据字段或类级别特征(例如注释或方法)的存在选择性地匹配自定义转换逻辑。
例如,当从 String 字段转换为 Date 字段时,如果目标字段也已使用 @DateTimeFormat,则实现可能会返回 true。
作为另一个示例,当从 String 字段转换为 Account 字段时,
如果目标 Account 类定义了公共静态 findAccount(String) 方法,则实现可能会返回 true。
*/
public interface ConditionalConverter {
/**
* 只有满足条件的时候,才会去尝试进行类型转换
*/
boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}
我相信大部分人第一眼看到这个接口的时候,都会思考spring为什么不把这个matches方法放到Converter和GenericConverter接口中去呢?
当然,spring这样做没有错,因为这样做符合接口的单一职责原则,子类可以选择性的组合各个不同的接口,来实现不同的功能,而不需要说实现一个接口,里面百分之50的方法都是无效的。
这就像搭积木,直接给你一个完整的不可分割的房子好呢? 还是给你一堆可拆卸积木好呢?
当然需要看情况,因为对于小项目而言,或许一个小房子就够了,但是对于spring这种大别墅而言,显然可以灵活组装的积木来的更加实用一些
public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter {
}
ConditionalGenericConverter 相当于是一个条件性的通用的转换器
这里也是挑了一个简单的实现来进行讲解
final class StringToArrayConverter implements ConditionalGenericConverter {
private final ConversionService conversionService;
public StringToArrayConverter(ConversionService conversionService) {
this.conversionService = conversionService;
}
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(new ConvertiblePair(String.class, Object[].class));
}
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return ConversionUtils.canConvertElements(sourceType, targetType.getElementTypeDescriptor(),
this.conversionService);
}
@Override
@Nullable
public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return null;
}
String string = (String) source;
//字符串按逗号分隔,得到数组
String[] fields = StringUtils.commaDelimitedListToStringArray(string);
TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();
Assert.state(targetElementType != null, "No target element type");
Object target = Array.newInstance(targetElementType.getType(), fields.length);
for (int i = 0; i < fields.length; i++) {
String sourceElement = fields[i];
Object targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, targetElementType);
Array.set(target, i, targetElement);
}
return target;
}
}
public class PropertyPlaceholderHelper {
private static final Log logger = LogFactory.getLog(PropertyPlaceholderHelper.class);
//已经知晓的占位符集合
private static final Map<String, String> wellKnownSimplePrefixes = new HashMap<>(4);
static {
wellKnownSimplePrefixes.put("}", "{");
wellKnownSimplePrefixes.put("]", "[");
wellKnownSimplePrefixes.put(")", "(");
}
//下面这五个属性不重复了,忘记的,直接翻到最上面重新看一遍
private final String placeholderPrefix;
private final String placeholderSuffix;
private final String simplePrefix;
@Nullable
private final String valueSeparator;
private final boolean ignoreUnresolvablePlaceholders;
public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix) {
this(placeholderPrefix, placeholderSuffix, null, true);
}
public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix,
@Nullable String valueSeparator, boolean ignoreUnresolvablePlaceholders) {
Assert.notNull(placeholderPrefix, "'placeholderPrefix' must not be null");
Assert.notNull(placeholderSuffix, "'placeholderSuffix' must not be null");
this.placeholderPrefix = placeholderPrefix;
this.placeholderSuffix = placeholderSuffix;
String simplePrefixForSuffix = wellKnownSimplePrefixes.get(this.placeholderSuffix);
if (simplePrefixForSuffix != null && this.placeholderPrefix.endsWith(simplePrefixForSuffix)) {
this.simplePrefix = simplePrefixForSuffix;
}
else {
this.simplePrefix = this.placeholderPrefix;
}
this.valueSeparator = valueSeparator;
this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;
}
/**
* 将格式为 ${name} 的所有占位符替换为提供的属性中的相应属性。
*/
public String replacePlaceholders(String value, final Properties properties) {
Assert.notNull(properties, "'properties' must not be null");
//拿着key去Properties寻找value--Properties算是一种属性源
return replacePlaceholders(value, properties::getProperty);
}
/**
*目的和上面一样
*/
public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
Assert.notNull(value, "'value' must not be null");
return parseStringValue(value, placeholderResolver, null);
}
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) {
//定位my name is ${name}中name字符串
String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
String originalPlaceholder = placeholder;
if (visitedPlaceholders == null) {
visitedPlaceholders = new HashSet<>(4);
}
if (!visitedPlaceholders.add(originalPlaceholder)) {
throw new IllegalArgumentException(
"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
}
// Recursive invocation, parsing placeholders contained in the placeholder key.
placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
// Now obtain the value for the fully resolved key...
//解析name这个占位符对应的value
String propVal = placeholderResolver.resolvePlaceholder(placeholder);
//如果解析完发现找不到,value为null,那么再看一下有无:即默认值
if (propVal == null && this.valueSeparator != null) {
int separatorIndex = placeholder.indexOf(this.valueSeparator);
if (separatorIndex != -1) {
//例如:${port:8080}
//actualPlaceholder : port
String actualPlaceholder = placeholder.substring(0, separatorIndex);
//defaultValue : 8080
String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
//如果解析完发现port为null
propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
if (propVal == null) {
//那么返回默认值8080
propVal = defaultValue;
}
}
}
if (propVal != null) {
// Recursive invocation, parsing placeholders contained in the
// previously resolved placeholder value.
//为了解决类似这种问题: ${name:${dhy.name}}--->如果没找到使用默认值
//那么上面返回的是应该是${dhy.name},此时还需要进行解析
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();
}
private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
int index = startIndex + this.placeholderPrefix.length();
int withinNestedPlaceholder = 0;
while (index < buf.length()) {
if (StringUtils.substringMatch(buf, index, this.placeholderSuffix)) {
if (withinNestedPlaceholder > 0) {
withinNestedPlaceholder--;
index = index + this.placeholderSuffix.length();
}
else {
return index;
}
}
else if (StringUtils.substringMatch(buf, index, this.simplePrefix)) {
withinNestedPlaceholder++;
index = index + this.simplePrefix.length();
}
else {
index++;
}
}
return -1;
}
/**
* Strategy interface used to resolve replacement values for placeholders contained in Strings.
*/
@FunctionalInterface
public interface PlaceholderResolver {
/**
* 举例: ${name},那么传给resolvePlaceholder的是name,即key,不同的数据源可能会拿着这个key去不同的地方
* 寻找value
*/
@Nullable
String resolvePlaceholder(String placeholderName);
}
}
测试:
public class PropertyResolverTest {
public static void main(String[] args) {
PropertyPlaceholderHelper propertyPlaceholderHelper
=new PropertyPlaceholderHelper("<",">","?",true);
String str = propertyPlaceholderHelper.replacePlaceholders("大忽悠当前工作目录为:<user.dir>", System::getProperty);
System.out.println(str);
}
}
这个组件是可以单独拿出来使用的
public abstract class PropertySource<T> {
protected final Log logger = LogFactory.getLog(getClass());
//属性源对应的名字
protected final String name;
//属性源
protected final T source;
public PropertySource(String name, T source) {
Assert.hasText(name, "Property source name must contain at least one character");
Assert.notNull(source, "Property source must not be null");
this.name = name;
this.source = source;
}
@SuppressWarnings("unchecked")
public PropertySource(String name) {
this(name, (T) new Object());
}
public String getName() {
return this.name;
}
public T getSource() {
return this.source;
}
public boolean containsProperty(String name) {
return (getProperty(name) != null);
}
//子类实现,因为需要根据不同属性源进行处理
@Nullable
public abstract Object getProperty(String name);
....
/**
Return a PropertySource implementation intended for collection comparison purposes only.
Primarily for internal use, but given a collection of PropertySource objects, may be used as follows:
List > sources = new ArrayList >();
sources.add(new MapPropertySource("sourceA", mapA));
sources.add(new MapPropertySource("sourceB", mapB));
assert sources.contains(PropertySource.named("sourceA"));
assert sources.contains(PropertySource.named("sourceB"));
assert !sources.contains(PropertySource.named("sourceC"));
The returned PropertySource will throw UnsupportedOperationException if any methods other than equals(Object), hashCode(), and toString() are called.
Params:
name – the name of the comparison PropertySource to be created and returned.
*/
public static PropertySource<?> named(String name) {
return new ComparisonPropertySource(name);
}
/**
在应用程序上下文创建时无法立即初始化实际属性源的情况下,PropertySource 将用作占位符。
例如,基于 ServletContext 的属性源必须等到 ServletContext 对象对其封闭的 ApplicationContext 可用。
在这种情况下,应该使用存根来保存属性源的预期默认位置顺序,然后在上下文刷新期间被替换。
*/
public static class StubPropertySource extends PropertySource<Object> {
public StubPropertySource(String name) {
super(name, new Object());
}
/**
* Always returns {@code null}.
*/
@Override
@Nullable
public String getProperty(String name) {
return null;
}
}
/**
* A {@code PropertySource} implementation intended for collection comparison
* purposes.
*
* @see PropertySource#named(String)
*/
static class ComparisonPropertySource extends StubPropertySource {
private static final String USAGE_ERROR =
"ComparisonPropertySource instances are for use with collection comparison only";
public ComparisonPropertySource(String name) {
super(name);
}
@Override
public Object getSource() {
throw new UnsupportedOperationException(USAGE_ERROR);
}
@Override
public boolean containsProperty(String name) {
throw new UnsupportedOperationException(USAGE_ERROR);
}
@Override
@Nullable
public String getProperty(String name) {
throw new UnsupportedOperationException(USAGE_ERROR);
}
}
}
该类作为一个顶层接口,也没干啥,主要就是规定了一个数据源作为属性的来源,并且让这个数据源关联一个名字
来看一下Properties作为数据源的场景
public class PropertiesPropertySource extends MapPropertySource {
....
}
因为PropertiesPropertySource并不是直接实现的PropertySource接口,因此我们先来看一波他的父类实现
MapPropertySource 实现了EnumerablePropertySource
public abstract class EnumerablePropertySource<T> extends PropertySource<T> {
public EnumerablePropertySource(String name, T source) {
super(name, source);
}
protected EnumerablePropertySource(String name) {
super(name);
}
@Override
public boolean containsProperty(String name) {
return ObjectUtils.containsElement(getPropertyNames(), name);
}
/**
* 返回源对象包含的所有属性的名称(从不为空)。
*/
public abstract String[] getPropertyNames();
}
在来看MapPropertySource
public class MapPropertySource extends EnumerablePropertySource<Map<String, Object>> {
public MapPropertySource(String name, Map<String, Object> source) {
super(name, source);
}
@Override
@Nullable
public Object getProperty(String name) {
return this.source.get(name);
}
@Override
public boolean containsProperty(String name) {
return this.source.containsKey(name);
}
@Override
public String[] getPropertyNames() {
return StringUtils.toStringArray(this.source.keySet());
}
}
在来看其子类PropertiesPropertySource
public class PropertiesPropertySource extends MapPropertySource {
@SuppressWarnings({"rawtypes", "unchecked"})
public PropertiesPropertySource(String name, Properties source) {
super(name, (Map) source);
}
protected PropertiesPropertySource(String name, Map<String, Object> source) {
super(name, source);
}
@Override
public String[] getPropertyNames() {
synchronized (this.source) {
return super.getPropertyNames();
}
}
}
就很简单好吧
public interface PropertySources extends Iterable<PropertySource<?>> {
default Stream<PropertySource<?>> stream() {
return StreamSupport.stream(spliterator(), false);
}
/**
*根据名字找到对应的属性源
*/
boolean contains(String name);
/**
* 返回指定名字关联的属性源
*/
@Nullable
PropertySource<?> get(String name);
}
public class MutablePropertySources implements PropertySources {
//属性源集合
private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<>();
public MutablePropertySources() {
}
public MutablePropertySources(PropertySources propertySources) {
this();
for (PropertySource<?> propertySource : propertySources) {
addLast(propertySource);
}
}
@Override
public Iterator<PropertySource<?>> iterator() {
return this.propertySourceList.iterator();
}
@Override
public Spliterator<PropertySource<?>> spliterator() {
return Spliterators.spliterator(this.propertySourceList, 0);
}
@Override
public Stream<PropertySource<?>> stream() {
return this.propertySourceList.stream();
}
@Override
public boolean contains(String name) {
for (PropertySource<?> propertySource : this.propertySourceList) {
if (propertySource.getName().equals(name)) {
return true;
}
}
return false;
}
@Override
@Nullable
public PropertySource<?> get(String name) {
for (PropertySource<?> propertySource : this.propertySourceList) {
if (propertySource.getName().equals(name)) {
return propertySource;
}
}
return null;
}
/**
* Add the given property source object with highest precedence.
*/
public void addFirst(PropertySource<?> propertySource) {
synchronized (this.propertySourceList) {
removeIfPresent(propertySource);
this.propertySourceList.add(0, propertySource);
}
}
/**
* Add the given property source object with lowest precedence.
*/
public void addLast(PropertySource<?> propertySource) {
synchronized (this.propertySourceList) {
removeIfPresent(propertySource);
this.propertySourceList.add(propertySource);
}
}
/**
* Add the given property source object with precedence immediately higher
* than the named relative property source.
*/
public void addBefore(String relativePropertySourceName, PropertySource<?> propertySource) {
assertLegalRelativeAddition(relativePropertySourceName, propertySource);
synchronized (this.propertySourceList) {
removeIfPresent(propertySource);
int index = assertPresentAndGetIndex(relativePropertySourceName);
addAtIndex(index, propertySource);
}
}
/**
* Add the given property source object with precedence immediately lower
* than the named relative property source.
*/
public void addAfter(String relativePropertySourceName, PropertySource<?> propertySource) {
assertLegalRelativeAddition(relativePropertySourceName, propertySource);
synchronized (this.propertySourceList) {
removeIfPresent(propertySource);
int index = assertPresentAndGetIndex(relativePropertySourceName);
addAtIndex(index + 1, propertySource);
}
}
/**
* Return the precedence of the given property source, {@code -1} if not found.
*/
public int precedenceOf(PropertySource<?> propertySource) {
return this.propertySourceList.indexOf(propertySource);
}
/**
* Remove and return the property source with the given name, {@code null} if not found.
* @param name the name of the property source to find and remove
*/
@Nullable
public PropertySource<?> remove(String name) {
synchronized (this.propertySourceList) {
int index = this.propertySourceList.indexOf(PropertySource.named(name));
return (index != -1 ? this.propertySourceList.remove(index) : null);
}
}
/**
* Replace the property source with the given name with the given property source object.
* @param name the name of the property source to find and replace
* @param propertySource the replacement property source
* @throws IllegalArgumentException if no property source with the given name is present
* @see #contains
*/
public void replace(String name, PropertySource<?> propertySource) {
synchronized (this.propertySourceList) {
int index = assertPresentAndGetIndex(name);
this.propertySourceList.set(index, propertySource);
}
}
/**
* Return the number of {@link PropertySource} objects contained.
*/
public int size() {
return this.propertySourceList.size();
}
@Override
public String toString() {
return this.propertySourceList.toString();
}
/**
* Ensure that the given property source is not being added relative to itself.
*/
protected void assertLegalRelativeAddition(String relativePropertySourceName, PropertySource<?> propertySource) {
String newPropertySourceName = propertySource.getName();
if (relativePropertySourceName.equals(newPropertySourceName)) {
throw new IllegalArgumentException(
"PropertySource named '" + newPropertySourceName + "' cannot be added relative to itself");
}
}
/**
* Remove the given property source if it is present.
*/
protected void removeIfPresent(PropertySource<?> propertySource) {
this.propertySourceList.remove(propertySource);
}
/**
* Add the given property source at a particular index in the list.
*/
private void addAtIndex(int index, PropertySource<?> propertySource) {
removeIfPresent(propertySource);
this.propertySourceList.add(index, propertySource);
}
/**
* Assert that the named property source is present and return its index.
* @param name {@linkplain PropertySource#getName() name of the property source} to find
* @throws IllegalArgumentException if the named property source is not present
*/
private int assertPresentAndGetIndex(String name) {
int index = this.propertySourceList.indexOf(PropertySource.named(name));
if (index == -1) {
throw new IllegalArgumentException("PropertySource named '" + name + "' does not exist");
}
return index;
}
}
因为这个类比较简单,我就基本没写注释了,大家自己看一遍就差不多了
测试:
public class PropertyResolverTest {
public static void main(String[] args) {
PropertySource propertySource=new PropertiesPropertySource("system",System.getProperties());
MutablePropertySources propertySources=new MutablePropertySources();
propertySources.addFirst(propertySource);
PropertySourcesPropertyResolver propertyResolver=new PropertySourcesPropertyResolver(propertySources);
String property = propertyResolver.getProperty("user.dir");
System.out.println(property);
}
}
更多的内容关注下一讲
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://cjdhy.blog.csdn.net/article/details/124043348
内容来源于网络,如有侵权,请联系作者删除!