<context:property-placeholder>的做用是向Spring容器中注入一个属性占位解析器,用来处理BeanDefinition中的各类占位符,用配置文件的信息替换占位符。这是个自定义标签,Spring会使用PropertyPlaceholderBeanDefinitionParser解析它。java
这个标签能够定义各类属性数据结构
PS:localOverride的运用,若是localOverride=false,配置的优先级:environment > location > property-ref,若是localOverride=true,配置的优先级:environment < location < property-ref
我从源码进行分析,仔细看下这些属性是怎么运用的。app
这是个自定义标签,Spring会使用PropertyPlaceholderBeanDefinitionParser解析它。ide
@Override protected Class<?> getBeanClass(Element element) { // system-properties-mode=ENVIRONMENT if (element.getAttribute(SYSTEM_PROPERTIES_MODE_ATTRIB).equals(SYSTEM_PROPERTIES_MODE_DEFAULT)) { return PropertySourcesPlaceholderConfigurer.class; } return PropertyPlaceholderConfigurer.class; }
说明:post
将全部的属性,包括environment、location、properties-ref,组装到PropertySources对象中。而后使用PropertySources去获取须要替换属性的真实值,依次迭代PropertySource,返回第一个找到的值。PropertySources是PropertySource的数据结构,里面封装多个PropertySource对象。ui
解析占位符过程this
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { if (this.propertySources == null) { // 一、准备PropertySources属性 ... } // 二、解析占位符 processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources)); this.appliedPropertySources = this.propertySources; }
if (this.propertySources == null) { this.propertySources = new MutablePropertySources(); if (this.environment != null) { // 加入environment的PropertySource,名称为environmentProperties this.propertySources.addLast( new PropertySource<Environment>(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) { @Override public String getProperty(String key) { // 从environment中获取属性 return this.source.getProperty(key); } } ); } try { // 加入配置文件的的PropertySource,名称为localProperties PropertySource<?> localPropertySource = new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, mergeProperties()); // 若是localOverride=true,就优先使用localProperties里的属性。作法是把localProperties的属性放在environmentProperties的前面 if (this.localOverride) { this.propertySources.addFirst(localPropertySource); } else { this.propertySources.addLast(localPropertySource); } } catch (IOException ex) { throw new BeanInitializationException("Could not load properties", ex); } }
说明:spa
PS:localOverride的运用,若是localOverride=false,配置的优先级:environment > location > property-ref,若是localOverride=true,配置的优先级:environment < location < property-refdebug
protected Properties mergeProperties() throws IOException { Properties result = new Properties(); if (this.localOverride) { // 先加载location定义的文件,会被property-ref中的属性覆盖 // Load properties from file upfront, to let local properties override. loadProperties(result); } if (this.localProperties != null) { // 加载bean中定义的property对象 for (Properties localProp : this.localProperties) { CollectionUtils.mergePropertiesIntoMap(localProp, result); } } if (!this.localOverride) { // 后加载location定义的文件,会覆盖property-ref中的属性 // Load properties from file afterwards, to let those properties override. loadProperties(result); } return result; }
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, final ConfigurablePropertyResolver propertyResolver) throws BeansException { propertyResolver.setPlaceholderPrefix(this.placeholderPrefix); propertyResolver.setPlaceholderSuffix(this.placeholderSuffix); propertyResolver.setValueSeparator(this.valueSeparator); StringValueResolver valueResolver = strVal -> { String resolved = (ignoreUnresolvablePlaceholders ? propertyResolver.resolvePlaceholders(strVal) : propertyResolver.resolveRequiredPlaceholders(strVal)); if (trimValues) { resolved = resolved.trim(); } return (resolved.equals(nullValue) ? null : resolved); }; doProcessProperties(beanFactoryToProcess, valueResolver); }
说明:code
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; }