context:property-placeholder 标签解析

<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定义
@Override
protected 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接口。我们看具体实现
@Override
public 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
我们看到两个解析占位符的方法
@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);
      }
   });
}

最终是通过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进行了实现
@Override
protected 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));


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这段代码是一个Spring MVC项目的配置文件,用于配置一些关键的组件和功能。让我一一解释一下: 1. `<mvc:annotation-driven/>`:启用Spring MVC注解驱动,使得控制器中的注解生效。 2. `<context:component-scan base-package="com.dgy"/>`:指定需要扫描的包,将被注解标记的类作为组件进行扫描。 3. `<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">`:配置视图解析器,用于解析并定位JSP视图文件。 4. `<context:property-placeholder location="classpath:jdbc.properties"/>`:加载属性文件jdbc.properties中的配置信息。 5. `<bean id="datasource" class="com.alibaba.druid.pool.DruidDataSource">`:配置数据库连接池,使用阿里巴巴Druid连接池。 6. `<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">`:配置MyBatis的SqlSessionFactory,指定数据源。 7. `<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">`:配置MyBatis的Mapper接口扫描器,用于自动扫描并实例化Mapper接口的实现类。 8. `<tx:annotation-driven/>`:启用Spring事务注解驱动,使得注解标记的方法可以被事务管理。 9. `<aop:aspectj-autoproxy/>`:启用AOP自动代理,用于支持基于切面的编程。 10. `<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">`:配置事务管理器,使用Spring的DataSourceTransactionManager,将数据源注入事务管理器。 希望以上解释对您有所帮助!如果您还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值