context:property-placeholder 标签解析

来源:互联网 发布:涤纶网络丝织带 编辑:程序博客网 时间:2024/05/17 02:54
<context:property-placeholder location="classpath*:application.properties"/>
对应的handler
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
public class ContextNamespaceHandler extends NamespaceHandlerSupport {   @Override   public void init() {      registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());      registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());      registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());      registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());      registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());      registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());      registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());      registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());   }}
PropertyPlaceholderBeanDefinitionParser对context:property-placeholder标签进行解析
解析的模版方法由AbstractSingleBeanDefinitionParser.parseInternal定义
@Overrideprotected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {   BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();   String parentName = getParentName(element);   if (parentName != null) {      builder.getRawBeanDefinition().setParentName(parentName);   }   Class<?> beanClass = getBeanClass(element);   if (beanClass != null) {      builder.getRawBeanDefinition().setBeanClass(beanClass);   }   else {      String beanClassName = getBeanClassName(element);      if (beanClassName != null) {         builder.getRawBeanDefinition().setBeanClassName(beanClassName);      }   }   builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));   if (parserContext.isNested()) {      // Inner bean definition must receive same scope as containing bean.      builder.setScope(parserContext.getContainingBeanDefinition().getScope());   }   if (parserContext.isDefaultLazyInit()) {      // Default-lazy-init applies to custom bean definitions as well.      builder.setLazyInit(true);   }   doParse(element, parserContext, builder);   return builder.getBeanDefinition();}
其中重要的方法是getBeanClass和doParse
我们再看PropertyPlaceholderBeanDefinitionParser类它覆盖了两个方法
class PropertyPlaceholderBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser {   private static final String SYSTEM_PROPERTIES_MODE_ATTRIBUTE = "system-properties-mode";   private static final String SYSTEM_PROPERTIES_MODE_DEFAULT = "ENVIRONMENT";   @Override   protected Class<?> getBeanClass(Element element) {      // As of Spring 3.1, the default value of system-properties-mode has changed from      // 'FALLBACK' to 'ENVIRONMENT'. This latter value indicates that resolution of      // placeholders against system properties is a function of the Environment and      // its current set of PropertySources.      if (SYSTEM_PROPERTIES_MODE_DEFAULT.equals(element.getAttribute(SYSTEM_PROPERTIES_MODE_ATTRIBUTE))) {         return PropertySourcesPlaceholderConfigurer.class;      }      // The user has explicitly specified a value for system-properties-mode: revert to      // PropertyPlaceholderConfigurer to ensure backward compatibility with 3.0 and earlier.      return PropertyPlaceholderConfigurer.class;   }   @Override   protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {      super.doParse(element, parserContext, builder);      builder.addPropertyValue("ignoreUnresolvablePlaceholders",            Boolean.valueOf(element.getAttribute("ignore-unresolvable")));      String systemPropertiesModeName = element.getAttribute(SYSTEM_PROPERTIES_MODE_ATTRIBUTE);      if (StringUtils.hasLength(systemPropertiesModeName) &&            !systemPropertiesModeName.equals(SYSTEM_PROPERTIES_MODE_DEFAULT)) {         builder.addPropertyValue("systemPropertiesModeName", "SYSTEM_PROPERTIES_MODE_" + systemPropertiesModeName);      }      if (element.hasAttribute("value-separator")) {         builder.addPropertyValue("valueSeparator", element.getAttribute("value-separator"));      }      if (element.hasAttribute("trim-values")) {         builder.addPropertyValue("trimValues", element.getAttribute("trim-values"));      }      if (element.hasAttribute("null-value")) {         builder.addPropertyValue("nullValue", element.getAttribute("null-value"));      }   }}
实际上我们用的是PropertySourcesPlaceholderConfigurer这个类。PropertyPlaceholderConfigurer
是老版本。PropertySourcesPlaceholderConfigurer实现了BeanFactoryPostProcessor接口
context:property-placeholder 标签被解析后创建了PropertySourcesPlaceholderConfigurer对象,这个对象
又实现了BeanFactoryPostProcessor接口。我们看具体实现
@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {   if (this.propertySources == null) {      this.propertySources = new MutablePropertySources();      if (this.environment != null) {         this.propertySources.addLast(            new PropertySource<Environment>(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) {               @Override               public String getProperty(String key) {                  return this.source.getProperty(key);               }            }         );      }      try {         PropertySource<?> localPropertySource =               new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, mergeProperties());         if (this.localOverride) {            this.propertySources.addFirst(localPropertySource);         }         else {            this.propertySources.addLast(localPropertySource);         }      }      catch (IOException ex) {         throw new BeanInitializationException("Could not load properties", ex);      }   }   processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources));   this.appliedPropertySources = this.propertySources;}
创建了MutablePropertySources对象加入当前环境的属性信息,并加入我们标签指定的配置文件属性信息。
我们看
processProperties方法
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess,      final ConfigurablePropertyResolver propertyResolver) throws BeansException {   propertyResolver.setPlaceholderPrefix(this.placeholderPrefix);   propertyResolver.setPlaceholderSuffix(this.placeholderSuffix);   propertyResolver.setValueSeparator(this.valueSeparator);   StringValueResolver valueResolver = new StringValueResolver() {      @Override      public String resolveStringValue(String strVal) {         String resolved = (ignoreUnresolvablePlaceholders ?               propertyResolver.resolvePlaceholders(strVal) :               propertyResolver.resolveRequiredPlaceholders(strVal));         if (trimValues) {            resolved = resolved.trim();         }         return (resolved.equals(nullValue) ? null : resolved);      }   };   doProcessProperties(beanFactoryToProcess, valueResolver);}
占位符前缀设置为${ 后缀为} 和默认值分隔符是:
创建一个StringValueResolver 对象。String Value值的解析最终是通过propertyResolver.resolvePlaceholders(strVal)或
propertyResolver.resolveRequiredPlaceholders(strVal))
我们看doProcessProperties方法
protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,      StringValueResolver valueResolver) {   BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);   String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();   for (String curName : beanNames) {      // Check that we're not parsing our own bean definition,      // to avoid failing on unresolvable placeholders in properties file locations.      if (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) {         BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName);         try {            visitor.visitBeanDefinition(bd);         }         catch (Exception ex) {            throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex);         }      }   }   // New in Spring 2.5: resolve placeholders in alias target names and aliases as well.   beanFactoryToProcess.resolveAliases(valueResolver);   // New in Spring 3.0: resolve placeholders in embedded values such as annotation attributes.   beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);}
遍历BeanDefinition 并使用访问器模式对BeanDefinition 的各个属性进行遍历。我们看visitor.visitBeanDefinition(bd)方法的实现

public void visitBeanDefinition(BeanDefinition beanDefinition) {   visitParentName(beanDefinition);   visitBeanClassName(beanDefinition);   visitFactoryBeanName(beanDefinition);   visitFactoryMethodName(beanDefinition);   visitScope(beanDefinition);   visitPropertyValues(beanDefinition.getPropertyValues());   ConstructorArgumentValues cas = beanDefinition.getConstructorArgumentValues();   visitIndexedArgumentValues(cas.getIndexedArgumentValues());   visitGenericArgumentValues(cas.getGenericArgumentValues());}
我们看visitPropertyValues方法
protected void visitPropertyValues(MutablePropertyValues pvs) {   PropertyValue[] pvArray = pvs.getPropertyValues();   for (PropertyValue pv : pvArray) {      Object newVal = resolveValue(pv.getValue());      if (!ObjectUtils.nullSafeEquals(newVal, pv.getValue())) {         pvs.add(pv.getName(), newVal);      }   }}

我们看一下是怎么解析String的
protected String resolveStringValue(String strVal) {   if (this.valueResolver == null) {      throw new IllegalStateException("No StringValueResolver specified - pass a resolver " +            "object into the constructor or override the 'resolveStringValue' method");   }   String resolvedValue = this.valueResolver.resolveStringValue(strVal);   // Return original String if not modified.   return (strVal.equals(resolvedValue) ? strVal : resolvedValue);}
这个valueResolver就是之前创建的
StringValueResolver valueResolver = new StringValueResolver() {   @Override   public String resolveStringValue(String strVal) {      String resolved = (ignoreUnresolvablePlaceholders ?            propertyResolver.resolvePlaceholders(strVal) :            propertyResolver.resolveRequiredPlaceholders(strVal));      if (trimValues) {         resolved = resolved.trim();      }      return (resolved.equals(nullValue) ? null : resolved);   }};
propertyResolver是之前传人的。
processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources));
PropertySourcesPropertyResolver继承于AbstractPropertyResolver
我们看到两个解析占位符的方法
@Overridepublic String resolvePlaceholders(String text) {   if (this.nonStrictHelper == null) {      this.nonStrictHelper = createPlaceholderHelper(true);   }   return doResolvePlaceholders(text, this.nonStrictHelper);}@Overridepublic 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);      }   });}

最终是通过PropertyPlaceholderHelper的replacePlaceholders方法进行解析。
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 value, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {   StringBuilder result = new StringBuilder(value);   int startIndex = value.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");         }         // Recursive invocation, parsing placeholders contained in the placeholder key.         placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);         // Now obtain the value for the fully resolved key...         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) {            // 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();}
parseStringValue最终的属性查找是通过传入对象placeholderResolver的resolvePlaceholder(方法确定。
这个对象是之前传入的
return helper.replacePlaceholders(text, new PropertyPlaceholderHelper.PlaceholderResolver() {      @Override      public String resolvePlaceholder(String placeholderName) {         return getPropertyAsRawString(placeholderName);      }   });

resolvePlaceholder方法最终调用的是getPropertyAsRawString方法
PropertySourcesPropertyResolver对getPropertyAsRawString进行了实现
@Overrideprotected String getPropertyAsRawString(String key) {   return getProperty(key, String.class, false);}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() + "'");         }         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.isDebugEnabled()) {      logger.debug("Could not find key '" + key + "' in any property source");   }   return null;}

我们看这句代码
Object value = propertySource.getProperty(key);
propertySource就是之前我们传入的。
try {      PropertySource<?> localPropertySource =            new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, mergeProperties());      if (this.localOverride) {         this.propertySources.addFirst(localPropertySource);      }      else {         this.propertySources.addLast(localPropertySource);      }   }   catch (IOException ex) {      throw new BeanInitializationException("Could not load properties", ex);   }}processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources));


原创粉丝点击