001/* 002 * Copyright 2002-2019 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 java.util.Properties; 020 021import org.springframework.beans.BeansException; 022import org.springframework.core.Constants; 023import org.springframework.core.SpringProperties; 024import org.springframework.core.env.AbstractEnvironment; 025import org.springframework.lang.Nullable; 026import org.springframework.util.PropertyPlaceholderHelper; 027import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver; 028import org.springframework.util.StringValueResolver; 029 030/** 031 * {@link PlaceholderConfigurerSupport} subclass that resolves ${...} placeholders against 032 * {@link #setLocation local} {@link #setProperties properties} and/or system properties 033 * and environment variables. 034 * 035 * <p>{@link PropertyPlaceholderConfigurer} is still appropriate for use when: 036 * <ul> 037 * <li>the {@code spring-context} module is not available (i.e., one is using Spring's 038 * {@code BeanFactory} API as opposed to {@code ApplicationContext}). 039 * <li>existing configuration makes use of the {@link #setSystemPropertiesMode(int) "systemPropertiesMode"} 040 * and/or {@link #setSystemPropertiesModeName(String) "systemPropertiesModeName"} properties. 041 * Users are encouraged to move away from using these settings, and rather configure property 042 * source search order through the container's {@code Environment}; however, exact preservation 043 * of functionality may be maintained by continuing to use {@code PropertyPlaceholderConfigurer}. 044 * </ul> 045 * 046 * @author Juergen Hoeller 047 * @author Chris Beams 048 * @since 02.10.2003 049 * @see #setSystemPropertiesModeName 050 * @see PlaceholderConfigurerSupport 051 * @see PropertyOverrideConfigurer 052 * @deprecated as of 5.2; use {@code org.springframework.context.support.PropertySourcesPlaceholderConfigurer} 053 * instead which is more flexible through taking advantage of the {@link org.springframework.core.env.Environment} 054 * and {@link org.springframework.core.env.PropertySource} mechanisms. 055 */ 056@Deprecated 057public class PropertyPlaceholderConfigurer extends PlaceholderConfigurerSupport { 058 059 /** Never check system properties. */ 060 public static final int SYSTEM_PROPERTIES_MODE_NEVER = 0; 061 062 /** 063 * Check system properties if not resolvable in the specified properties. 064 * This is the default. 065 */ 066 public static final int SYSTEM_PROPERTIES_MODE_FALLBACK = 1; 067 068 /** 069 * Check system properties first, before trying the specified properties. 070 * This allows system properties to override any other property source. 071 */ 072 public static final int SYSTEM_PROPERTIES_MODE_OVERRIDE = 2; 073 074 075 private static final Constants constants = new Constants(PropertyPlaceholderConfigurer.class); 076 077 private int systemPropertiesMode = SYSTEM_PROPERTIES_MODE_FALLBACK; 078 079 private boolean searchSystemEnvironment = 080 !SpringProperties.getFlag(AbstractEnvironment.IGNORE_GETENV_PROPERTY_NAME); 081 082 083 /** 084 * Set the system property mode by the name of the corresponding constant, 085 * e.g. "SYSTEM_PROPERTIES_MODE_OVERRIDE". 086 * @param constantName name of the constant 087 * @see #setSystemPropertiesMode 088 */ 089 public void setSystemPropertiesModeName(String constantName) throws IllegalArgumentException { 090 this.systemPropertiesMode = constants.asNumber(constantName).intValue(); 091 } 092 093 /** 094 * Set how to check system properties: as fallback, as override, or never. 095 * For example, will resolve ${user.dir} to the "user.dir" system property. 096 * <p>The default is "fallback": If not being able to resolve a placeholder 097 * with the specified properties, a system property will be tried. 098 * "override" will check for a system property first, before trying the 099 * specified properties. "never" will not check system properties at all. 100 * @see #SYSTEM_PROPERTIES_MODE_NEVER 101 * @see #SYSTEM_PROPERTIES_MODE_FALLBACK 102 * @see #SYSTEM_PROPERTIES_MODE_OVERRIDE 103 * @see #setSystemPropertiesModeName 104 */ 105 public void setSystemPropertiesMode(int systemPropertiesMode) { 106 this.systemPropertiesMode = systemPropertiesMode; 107 } 108 109 /** 110 * Set whether to search for a matching system environment variable 111 * if no matching system property has been found. Only applied when 112 * "systemPropertyMode" is active (i.e. "fallback" or "override"), right 113 * after checking JVM system properties. 114 * <p>Default is "true". Switch this setting off to never resolve placeholders 115 * against system environment variables. Note that it is generally recommended 116 * to pass external values in as JVM system properties: This can easily be 117 * achieved in a startup script, even for existing environment variables. 118 * @see #setSystemPropertiesMode 119 * @see System#getProperty(String) 120 * @see System#getenv(String) 121 */ 122 public void setSearchSystemEnvironment(boolean searchSystemEnvironment) { 123 this.searchSystemEnvironment = searchSystemEnvironment; 124 } 125 126 /** 127 * Resolve the given placeholder using the given properties, performing 128 * a system properties check according to the given mode. 129 * <p>The default implementation delegates to {@code resolvePlaceholder 130 * (placeholder, props)} before/after the system properties check. 131 * <p>Subclasses can override this for custom resolution strategies, 132 * including customized points for the system properties check. 133 * @param placeholder the placeholder to resolve 134 * @param props the merged properties of this configurer 135 * @param systemPropertiesMode the system properties mode, 136 * according to the constants in this class 137 * @return the resolved value, of null if none 138 * @see #setSystemPropertiesMode 139 * @see System#getProperty 140 * @see #resolvePlaceholder(String, java.util.Properties) 141 */ 142 @Nullable 143 protected String resolvePlaceholder(String placeholder, Properties props, int systemPropertiesMode) { 144 String propVal = null; 145 if (systemPropertiesMode == SYSTEM_PROPERTIES_MODE_OVERRIDE) { 146 propVal = resolveSystemProperty(placeholder); 147 } 148 if (propVal == null) { 149 propVal = resolvePlaceholder(placeholder, props); 150 } 151 if (propVal == null && systemPropertiesMode == SYSTEM_PROPERTIES_MODE_FALLBACK) { 152 propVal = resolveSystemProperty(placeholder); 153 } 154 return propVal; 155 } 156 157 /** 158 * Resolve the given placeholder using the given properties. 159 * The default implementation simply checks for a corresponding property key. 160 * <p>Subclasses can override this for customized placeholder-to-key mappings 161 * or custom resolution strategies, possibly just using the given properties 162 * as fallback. 163 * <p>Note that system properties will still be checked before respectively 164 * after this method is invoked, according to the system properties mode. 165 * @param placeholder the placeholder to resolve 166 * @param props the merged properties of this configurer 167 * @return the resolved value, of {@code null} if none 168 * @see #setSystemPropertiesMode 169 */ 170 @Nullable 171 protected String resolvePlaceholder(String placeholder, Properties props) { 172 return props.getProperty(placeholder); 173 } 174 175 /** 176 * Resolve the given key as JVM system property, and optionally also as 177 * system environment variable if no matching system property has been found. 178 * @param key the placeholder to resolve as system property key 179 * @return the system property value, or {@code null} if not found 180 * @see #setSearchSystemEnvironment 181 * @see System#getProperty(String) 182 * @see System#getenv(String) 183 */ 184 @Nullable 185 protected String resolveSystemProperty(String key) { 186 try { 187 String value = System.getProperty(key); 188 if (value == null && this.searchSystemEnvironment) { 189 value = System.getenv(key); 190 } 191 return value; 192 } 193 catch (Throwable ex) { 194 if (logger.isDebugEnabled()) { 195 logger.debug("Could not access system property '" + key + "': " + ex); 196 } 197 return null; 198 } 199 } 200 201 202 /** 203 * Visit each bean definition in the given bean factory and attempt to replace ${...} property 204 * placeholders with values from the given properties. 205 */ 206 @Override 207 protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) 208 throws BeansException { 209 210 StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props); 211 doProcessProperties(beanFactoryToProcess, valueResolver); 212 } 213 214 215 private class PlaceholderResolvingStringValueResolver implements StringValueResolver { 216 217 private final PropertyPlaceholderHelper helper; 218 219 private final PlaceholderResolver resolver; 220 221 public PlaceholderResolvingStringValueResolver(Properties props) { 222 this.helper = new PropertyPlaceholderHelper( 223 placeholderPrefix, placeholderSuffix, valueSeparator, ignoreUnresolvablePlaceholders); 224 this.resolver = new PropertyPlaceholderConfigurerResolver(props); 225 } 226 227 @Override 228 @Nullable 229 public String resolveStringValue(String strVal) throws BeansException { 230 String resolved = this.helper.replacePlaceholders(strVal, this.resolver); 231 if (trimValues) { 232 resolved = resolved.trim(); 233 } 234 return (resolved.equals(nullValue) ? null : resolved); 235 } 236 } 237 238 239 private final class PropertyPlaceholderConfigurerResolver implements PlaceholderResolver { 240 241 private final Properties props; 242 243 private PropertyPlaceholderConfigurerResolver(Properties props) { 244 this.props = props; 245 } 246 247 @Override 248 @Nullable 249 public String resolvePlaceholder(String placeholderName) { 250 return PropertyPlaceholderConfigurer.this.resolvePlaceholder(placeholderName, 251 this.props, systemPropertiesMode); 252 } 253 } 254 255}