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