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}" );