PropertyResolver
在Spring
中的作用是负责属性解析,例如在XML
中替换占位符(${}
)属性,@Value
注解等
PropertyResolver
PropertySource & PropertySources 在介绍PropertyResolver
之前,先介绍下PropertySource
和PropertySources
。PropertySource
可以看做是包含了name/value
的对象,而PropertySources
则是由多个PropertySource
组成的对象
PropertySource 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 public abstract class PropertySource <T> { 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 ); } public abstract Object getProperty (String name) ; public static PropertySource<?> named(String name) { return new ComparisonPropertySource (name); } public static class StubPropertySource extends PropertySource <Object> { public StubPropertySource (String name) { super (name, new Object ()); } @Override public String getProperty (String name) { return null ; } } 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 public String getProperty (String name) { throw new UnsupportedOperationException (USAGE_ERROR); } @Override public String toString () { return String.format("%s [name='%s']" , getClass().getSimpleName(), this .name); } } }
PropertySources 1 2 3 4 5 6 7 8 public interface PropertySources extends Iterable <PropertySource<?>> { boolean contains (String name) ; PropertySource<?> get(String name); }
MutablePropertySources
是PropertySources
的默认实现,保存了List<PropertySource<?>>
(虽然是list
但是实际上通过PropertySources.name
保证了每个PropertySources
唯一性),并且还添加了添加/删除等方法,例如addFirst(PropertySource<?> propertySource)
,remove(String name)
等
PropertySourcesPropertyResolver PropertySourcesPropertyResolver
做的事,就是循环PropertySources
,根据属性名称从PropertySource
中获取属性值,并且对属性值做占位符解析替换
写个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public static void main (String[] args) { Map<String, Object> mapProperties = new HashMap <>(); mapProperties.put("name" , "Allen" ); mapProperties.put("age" , 12 ); mapProperties.put("nickname" , "${name}|${age}" ); MutablePropertySources propertySources = new MutablePropertySources (); propertySources.addLast(new MapPropertySource ("user" , mapProperties)); PropertySourcesPropertyResolver propertySourcesPropertyResolver = new PropertySourcesPropertyResolver (propertySources); propertySourcesPropertyResolver.setIgnoreUnresolvableNestedPlaceholders(false ); propertySourcesPropertyResolver.setValueSeparator(":" ); propertySourcesPropertyResolver.setPlaceholderSuffix("}" ); propertySourcesPropertyResolver.setPlaceholderPrefix("${" ); System.out.println("name -> " + propertySourcesPropertyResolver.getProperty("name" )); System.out.println("age -> " + propertySourcesPropertyResolver.getProperty("age" )); System.out.println("nickname -> " + propertySourcesPropertyResolver.getProperty("nickname" )); System.out.println("introduction -> " + propertySourcesPropertyResolver.resolvePlaceholders("My name is ${name}, I'm ${age}." )); }
getProperty()方法实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 protected <T> T getProperty (String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) { boolean debugEnabled = logger.isDebugEnabled(); if (logger.isTraceEnabled()) { logger.trace(String.format("getProperty(\"%s\", %s)" , key, targetValueType.getSimpleName())); } if (this .propertySources != null ) { for (PropertySource<?> propertySource : this .propertySources) { if (debugEnabled) { logger.debug(String.format("Searching for key '%s' in [%s]" , key, propertySource.getName())); } Object value = propertySource.getProperty(key); if (value != null ) { Class<?> valueType = value.getClass(); if (resolveNestedPlaceholders && value instanceof String) { value = resolveNestedPlaceholders((String) value); } if (debugEnabled) { logger.debug(String.format("Found key '%s' in [%s] with type [%s] and value '%s'" , key, propertySource.getName(), valueType.getSimpleName(), value)); } if (!this .conversionService.canConvert(valueType, targetValueType)) { throw new IllegalArgumentException (String.format( "Cannot convert value [%s] from source type [%s] to target type [%s]" , value, valueType.getSimpleName(), targetValueType.getSimpleName())); } return this .conversionService.convert(value, targetValueType); } } } if (debugEnabled) { logger.debug(String.format("Could not find key '%s' in any property source. Returning [null]" , key)); } return null ; }
resolveNestedPlaceholders()
调用的是AbstractPropertyResolver.resolveNestedPlaceholders()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 protected String resolveNestedPlaceholders (String 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 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, new PropertyPlaceholderHelper .PlaceholderResolver() { @Override public String resolvePlaceholder (String placeholderName) { return getPropertyAsRawString(placeholderName); } }); } protected abstract String getPropertyAsRawString (String key) ;
可以看出,占位符处理工作是在PropertyPlaceholderHelper.replacePlaceholders()
中实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 public String replacePlaceholders (String value, PlaceholderResolver placeholderResolver) { Assert.notNull(value, "'value' must not be null" ); return parseStringValue(value, placeholderResolver, new HashSet <String>()); } protected String parseStringValue (String strVal, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) { StringBuilder result = new StringBuilder (strVal); int startIndex = strVal.indexOf(this .placeholderPrefix); 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.add(originalPlaceholder)) { throw new IllegalArgumentException ( "Circular placeholder reference '" + originalPlaceholder + "' in property definitions" ); } placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders); String propVal = placeholderResolver.resolvePlaceholder(placeholder); 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 ) { 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) { startIndex = result.indexOf(this .placeholderPrefix, endIndex + this .placeholderSuffix.length()); } else { throw new IllegalArgumentException ("Could not resolve placeholder '" + placeholder + "'" + " in string value \"" + strVal + "\"" ); } visitedPlaceholders.remove(originalPlaceholder); } else { startIndex = -1 ; } } return result.toString(); }
1.循环依赖
1 2 3 4 mapProperties.put("def" , "${abc}" ); mapProperties.put("abc" , "${def}" ); mapProperties.put("a" , "${a}" );
2.占位符递归
1 2 3 4 mapProperties.put("a" , "a" ); mapProperties.put("b" , "b" ); mapProperties.put("ab" , "${a}" ); mapProperties.put("abc" , "${a${b}}" );
3.分隔符使用
1 mapProperties.put("a" , "${abc:123}" );