001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.beans.factory.config; 018 019import org.springframework.beans.factory.BeanDefinitionStoreException; 020import org.springframework.beans.factory.BeanFactory; 021import org.springframework.beans.factory.BeanFactoryAware; 022import org.springframework.beans.factory.BeanNameAware; 023import org.springframework.util.StringValueResolver; 024 025/** 026 * Abstract base class for property resource configurers that resolve placeholders 027 * in bean definition property values. Implementations <em>pull</em> values from a 028 * properties file or other {@linkplain org.springframework.core.env.PropertySource 029 * property source} into bean definitions. 030 * 031 * <p>The default placeholder syntax follows the Ant / Log4J / JSP EL style: 032 * 033 * <pre class="code">${...}</pre> 034 * 035 * Example XML bean definition: 036 * 037 * <pre class="code"> 038 * <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"/> 039 * <property name="driverClassName" value="${driver}"/> 040 * <property name="url" value="jdbc:${dbname}"/> 041 * </bean> 042 * </pre> 043 * 044 * Example properties file: 045 * 046 * <pre class="code">driver=com.mysql.jdbc.Driver 047 * dbname=mysql:mydb</pre> 048 * 049 * Annotated bean definitions may take advantage of property replacement using 050 * the {@link org.springframework.beans.factory.annotation.Value @Value} annotation: 051 * 052 * <pre class="code">@Value("${person.age}")</pre> 053 * 054 * Implementations check simple property values, lists, maps, props, and bean names 055 * in bean references. Furthermore, placeholder values can also cross-reference 056 * other placeholders, like: 057 * 058 * <pre class="code">rootPath=myrootdir 059 * subPath=${rootPath}/subdir</pre> 060 * 061 * In contrast to {@link PropertyOverrideConfigurer}, subclasses of this type allow 062 * filling in of explicit placeholders in bean definitions. 063 * 064 * <p>If a configurer cannot resolve a placeholder, a {@link BeanDefinitionStoreException} 065 * will be thrown. If you want to check against multiple properties files, specify multiple 066 * resources via the {@link #setLocations locations} property. You can also define multiple 067 * configurers, each with its <em>own</em> placeholder syntax. Use {@link 068 * #ignoreUnresolvablePlaceholders} to intentionally suppress throwing an exception if a 069 * placeholder cannot be resolved. 070 * 071 * <p>Default property values can be defined globally for each configurer instance 072 * via the {@link #setProperties properties} property, or on a property-by-property basis 073 * using the default value separator which is {@code ":"} by default and 074 * customizable via {@link #setValueSeparator(String)}. 075 * 076 * <p>Example XML property with default value: 077 * 078 * <pre class="code"> 079 * <property name="url" value="jdbc:${dbname:defaultdb}"/> 080 * </pre> 081 * 082 * @author Chris Beams 083 * @author Juergen Hoeller 084 * @since 3.1 085 * @see PropertyPlaceholderConfigurer 086 * @see org.springframework.context.support.PropertySourcesPlaceholderConfigurer 087 */ 088public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfigurer 089 implements BeanNameAware, BeanFactoryAware { 090 091 /** Default placeholder prefix: {@value} */ 092 public static final String DEFAULT_PLACEHOLDER_PREFIX = "${"; 093 094 /** Default placeholder suffix: {@value} */ 095 public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}"; 096 097 /** Default value separator: {@value} */ 098 public static final String DEFAULT_VALUE_SEPARATOR = ":"; 099 100 101 /** Defaults to {@value #DEFAULT_PLACEHOLDER_PREFIX} */ 102 protected String placeholderPrefix = DEFAULT_PLACEHOLDER_PREFIX; 103 104 /** Defaults to {@value #DEFAULT_PLACEHOLDER_SUFFIX} */ 105 protected String placeholderSuffix = DEFAULT_PLACEHOLDER_SUFFIX; 106 107 /** Defaults to {@value #DEFAULT_VALUE_SEPARATOR} */ 108 protected String valueSeparator = DEFAULT_VALUE_SEPARATOR; 109 110 protected boolean trimValues = false; 111 112 protected String nullValue; 113 114 protected boolean ignoreUnresolvablePlaceholders = false; 115 116 private String beanName; 117 118 private BeanFactory beanFactory; 119 120 121 /** 122 * Set the prefix that a placeholder string starts with. 123 * The default is {@value #DEFAULT_PLACEHOLDER_PREFIX}. 124 */ 125 public void setPlaceholderPrefix(String placeholderPrefix) { 126 this.placeholderPrefix = placeholderPrefix; 127 } 128 129 /** 130 * Set the suffix that a placeholder string ends with. 131 * The default is {@value #DEFAULT_PLACEHOLDER_SUFFIX}. 132 */ 133 public void setPlaceholderSuffix(String placeholderSuffix) { 134 this.placeholderSuffix = placeholderSuffix; 135 } 136 137 /** 138 * Specify the separating character between the placeholder variable 139 * and the associated default value, or {@code null} if no such 140 * special character should be processed as a value separator. 141 * The default is {@value #DEFAULT_VALUE_SEPARATOR}. 142 */ 143 public void setValueSeparator(String valueSeparator) { 144 this.valueSeparator = valueSeparator; 145 } 146 147 /** 148 * Specify whether to trim resolved values before applying them, 149 * removing superfluous whitespace from the beginning and end. 150 * <p>Default is {@code false}. 151 * @since 4.3 152 */ 153 public void setTrimValues(boolean trimValues) { 154 this.trimValues = trimValues; 155 } 156 157 /** 158 * Set a value that should be treated as {@code null} when resolved 159 * as a placeholder value: e.g. "" (empty String) or "null". 160 * <p>Note that this will only apply to full property values, 161 * not to parts of concatenated values. 162 * <p>By default, no such null value is defined. This means that 163 * there is no way to express {@code null} as a property value 164 * unless you explicitly map a corresponding value here. 165 */ 166 public void setNullValue(String nullValue) { 167 this.nullValue = nullValue; 168 } 169 170 /** 171 * Set whether to ignore unresolvable placeholders. 172 * <p>Default is "false": An exception will be thrown if a placeholder fails 173 * to resolve. Switch this flag to "true" in order to preserve the placeholder 174 * String as-is in such a case, leaving it up to other placeholder configurers 175 * to resolve it. 176 */ 177 public void setIgnoreUnresolvablePlaceholders(boolean ignoreUnresolvablePlaceholders) { 178 this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders; 179 } 180 181 /** 182 * Only necessary to check that we're not parsing our own bean definition, 183 * to avoid failing on unresolvable placeholders in properties file locations. 184 * The latter case can happen with placeholders for system properties in 185 * resource locations. 186 * @see #setLocations 187 * @see org.springframework.core.io.ResourceEditor 188 */ 189 @Override 190 public void setBeanName(String beanName) { 191 this.beanName = beanName; 192 } 193 194 /** 195 * Only necessary to check that we're not parsing our own bean definition, 196 * to avoid failing on unresolvable placeholders in properties file locations. 197 * The latter case can happen with placeholders for system properties in 198 * resource locations. 199 * @see #setLocations 200 * @see org.springframework.core.io.ResourceEditor 201 */ 202 @Override 203 public void setBeanFactory(BeanFactory beanFactory) { 204 this.beanFactory = beanFactory; 205 } 206 207 208 protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess, 209 StringValueResolver valueResolver) { 210 211 BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver); 212 213 String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames(); 214 for (String curName : beanNames) { 215 // Check that we're not parsing our own bean definition, 216 // to avoid failing on unresolvable placeholders in properties file locations. 217 if (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) { 218 BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName); 219 try { 220 visitor.visitBeanDefinition(bd); 221 } 222 catch (Exception ex) { 223 throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex); 224 } 225 } 226 } 227 228 // New in Spring 2.5: resolve placeholders in alias target names and aliases as well. 229 beanFactoryToProcess.resolveAliases(valueResolver); 230 231 // New in Spring 3.0: resolve placeholders in embedded values such as annotation attributes. 232 beanFactoryToProcess.addEmbeddedValueResolver(valueResolver); 233 } 234 235}