Skip to content

Commit 866c784

Browse files
committed
Introduced SpringProperties class and optional "spring.properties" file
This in particular allows for specifying "spring.getenv.ignore" and "spring.beaninfo.ignore" in a local way within the application, in case that JVM-level system properties are locked. Issue: SPR-9014 Issue: SPR-11297 (cherry picked from commit 8543b91)
1 parent fc36184 commit 866c784

File tree

5 files changed

+197
-57
lines changed

5 files changed

+197
-57
lines changed

spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.apache.commons.logging.Log;
3434
import org.apache.commons.logging.LogFactory;
3535

36+
import org.springframework.core.SpringProperties;
3637
import org.springframework.core.io.support.SpringFactoriesLoader;
3738
import org.springframework.util.ClassUtils;
3839
import org.springframework.util.StringUtils;
@@ -114,17 +115,7 @@ public class CachedIntrospectionResults {
114115

115116

116117
static {
117-
boolean ignoreValue;
118-
try {
119-
ignoreValue = "true".equalsIgnoreCase(System.getProperty(IGNORE_BEANINFO_PROPERTY_NAME));
120-
}
121-
catch (Throwable ex) {
122-
if (logger.isDebugEnabled()) {
123-
logger.debug("Could not obtain system property '" + IGNORE_BEANINFO_PROPERTY_NAME + "': " + ex);
124-
}
125-
ignoreValue = false;
126-
}
127-
shouldIntrospectorIgnoreBeaninfoClasses = ignoreValue;
118+
shouldIntrospectorIgnoreBeaninfoClasses = SpringProperties.getFlag(IGNORE_BEANINFO_PROPERTY_NAME);
128119
}
129120

130121

@@ -293,16 +284,19 @@ private CachedIntrospectionResults(Class<?> beanClass) throws BeansException {
293284
}
294285
this.beanInfo = beanInfo;
295286

296-
// Immediately remove class from Introspector cache, to allow for proper
297-
// garbage collection on class loader shutdown - we cache it here anyway,
298-
// in a GC-friendly manner. In contrast to CachedIntrospectionResults,
299-
// Introspector does not use WeakReferences as values of its WeakHashMap!
300-
Class<?> classToFlush = beanClass;
301-
do {
302-
Introspector.flushFromCaches(classToFlush);
303-
classToFlush = classToFlush.getSuperclass();
287+
// Only bother with flushFromCaches if the Introspector actually cached...
288+
if (!shouldIntrospectorIgnoreBeaninfoClasses) {
289+
// Immediately remove class from Introspector cache, to allow for proper
290+
// garbage collection on class loader shutdown - we cache it here anyway,
291+
// in a GC-friendly manner. In contrast to CachedIntrospectionResults,
292+
// Introspector does not use WeakReferences as values of its WeakHashMap!
293+
Class<?> classToFlush = beanClass;
294+
do {
295+
Introspector.flushFromCaches(classToFlush);
296+
classToFlush = classToFlush.getSuperclass();
297+
}
298+
while (classToFlush != null);
304299
}
305-
while (classToFlush != null);
306300

307301
if (logger.isTraceEnabled()) {
308302
logger.trace("Caching PropertyDescriptors for class [" + beanClass.getName() + "]");

spring-beans/src/main/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import org.springframework.beans.BeansException;
2323
import org.springframework.core.Constants;
24+
import org.springframework.core.SpringProperties;
2425
import org.springframework.core.env.AbstractEnvironment;
2526
import org.springframework.util.PropertyPlaceholderHelper;
2627
import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
@@ -84,7 +85,7 @@ public class PropertyPlaceholderConfigurer extends PlaceholderConfigurerSupport
8485
private int systemPropertiesMode = SYSTEM_PROPERTIES_MODE_FALLBACK;
8586

8687
private boolean searchSystemEnvironment =
87-
!"true".equalsIgnoreCase(System.getProperty(AbstractEnvironment.IGNORE_GETENV_PROPERTY_NAME));
88+
!SpringProperties.getFlag(AbstractEnvironment.IGNORE_GETENV_PROPERTY_NAME);
8889

8990

9091
/**
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
* Copyright 2002-2013 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.core;
18+
19+
import java.io.IOException;
20+
import java.io.InputStream;
21+
import java.net.URL;
22+
import java.util.Properties;
23+
24+
import org.apache.commons.logging.Log;
25+
import org.apache.commons.logging.LogFactory;
26+
27+
/**
28+
* Static holder for local Spring properties, i.e. defined at the Spring library level.
29+
*
30+
* <p>Reads a {@code spring.properties} file from the root of the Spring library classpath,
31+
* and also allows for programmatically setting properties through {@link #setProperty}.
32+
* When checking a property, local entries are being checked first, then falling back
33+
* to JVM-level system properties through a {@link System#getProperty} check.
34+
*
35+
* <p>This is an alternative way to set Spring-related system properties such as
36+
* "spring.getenv.ignore" and "spring.beaninfo.ignore", in particular for scenarios
37+
* where JVM system properties are locked on the target platform (e.g. WebSphere).
38+
* See {@link #setFlag} for a convenient way to locally set such flags to "true".
39+
*
40+
* @author Juergen Hoeller
41+
* @since 3.2.7
42+
* @see org.springframework.core.env.AbstractEnvironment#IGNORE_GETENV_PROPERTY_NAME
43+
* @see org.springframework.beans.CachedIntrospectionResults#IGNORE_BEANINFO_PROPERTY_NAME
44+
*/
45+
public abstract class SpringProperties {
46+
47+
private static final Log logger = LogFactory.getLog(SpringProperties.class);
48+
49+
private static final Properties localProperties = new Properties();
50+
51+
52+
static {
53+
try {
54+
ClassLoader cl = SpringProperties.class.getClassLoader();
55+
URL url = cl.getResource("spring.properties");
56+
if (url != null) {
57+
logger.info("Found 'spring.properties' file in local classpath");
58+
InputStream is = url.openStream();
59+
try {
60+
localProperties.load(is);
61+
}
62+
finally {
63+
is.close();
64+
}
65+
}
66+
}
67+
catch (IOException ex) {
68+
if (logger.isInfoEnabled()) {
69+
logger.info("Could not load 'spring.properties' file from local classpath: " + ex);
70+
}
71+
}
72+
}
73+
74+
75+
/**
76+
* Programmatically set a local property, overriding an entry in the
77+
* {@code spring.properties} file (if any).
78+
* @param key the property key
79+
* @param value the associated property value, or {@code null} to reset it
80+
*/
81+
public static void setProperty(String key, String value) {
82+
if (value != null) {
83+
localProperties.setProperty(key, value);
84+
}
85+
else {
86+
localProperties.remove(key);
87+
}
88+
}
89+
90+
/**
91+
* Retrieve the property value for the given key, checking local Spring
92+
* properties first and falling back to JVM-level system properties.
93+
* @param key the property key
94+
* @return the associated property value, or {@code null} if none found
95+
*/
96+
public static String getProperty(String key) {
97+
String value = localProperties.getProperty(key);
98+
if (value == null) {
99+
try {
100+
value = System.getProperty(key);
101+
}
102+
catch (Throwable ex) {
103+
if (logger.isDebugEnabled()) {
104+
logger.debug("Could not retrieve system property '" + key + "': " + ex);
105+
}
106+
}
107+
}
108+
return value;
109+
}
110+
111+
/**
112+
* Programmatically set a local flag to "true", overriding an
113+
* entry in the {@code spring.properties} file (if any).
114+
* @param key the property key
115+
*/
116+
public static void setFlag(String key) {
117+
localProperties.put(key, Boolean.TRUE.toString());
118+
}
119+
120+
/**
121+
* Retrieve the flag for the given property key.
122+
* @param key the property key
123+
* @return {@code true} if the property is set to "true",
124+
* {@code} false otherwise
125+
*/
126+
public static boolean getFlag(String key) {
127+
return Boolean.parseBoolean(getProperty(key));
128+
}
129+
130+
}

spring-core/src/main/java/org/springframework/core/env/AbstractEnvironment.java

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.apache.commons.logging.Log;
2626
import org.apache.commons.logging.LogFactory;
2727

28+
import org.springframework.core.SpringProperties;
2829
import org.springframework.core.convert.support.ConfigurableConversionService;
2930
import org.springframework.util.Assert;
3031
import org.springframework.util.StringUtils;
@@ -369,15 +370,15 @@ public Map<String, Object> getSystemEnvironment() {
369370
catch (AccessControlException ex) {
370371
return (Map) new ReadOnlySystemAttributesMap() {
371372
@Override
372-
protected String getSystemAttribute(String variableName) {
373+
protected String getSystemAttribute(String attributeName) {
373374
try {
374-
return System.getenv(variableName);
375+
return System.getenv(attributeName);
375376
}
376377
catch (AccessControlException ex) {
377378
if (logger.isInfoEnabled()) {
378379
logger.info(format("Caught AccessControlException when accessing system " +
379380
"environment variable [%s]; its value will be returned [null]. Reason: %s",
380-
variableName, ex.getMessage()));
381+
attributeName, ex.getMessage()));
381382
}
382383
return null;
383384
}
@@ -396,15 +397,7 @@ protected String getSystemAttribute(String variableName) {
396397
* returning {@code true} if its value equals "true" in any case.
397398
*/
398399
protected boolean suppressGetenvAccess() {
399-
try {
400-
return "true".equalsIgnoreCase(System.getProperty(IGNORE_GETENV_PROPERTY_NAME));
401-
}
402-
catch (Throwable ex) {
403-
if (logger.isDebugEnabled()) {
404-
logger.debug("Could not obtain system property '" + IGNORE_GETENV_PROPERTY_NAME + "': " + ex);
405-
}
406-
return false;
407-
}
400+
return SpringProperties.getFlag(IGNORE_GETENV_PROPERTY_NAME);
408401
}
409402

410403
@SuppressWarnings("unchecked")
@@ -415,15 +408,15 @@ public Map<String, Object> getSystemProperties() {
415408
catch (AccessControlException ex) {
416409
return (Map) new ReadOnlySystemAttributesMap() {
417410
@Override
418-
protected String getSystemAttribute(String propertyName) {
411+
protected String getSystemAttribute(String attributeName) {
419412
try {
420-
return System.getProperty(propertyName);
413+
return System.getProperty(attributeName);
421414
}
422415
catch (AccessControlException ex) {
423416
if (logger.isInfoEnabled()) {
424417
logger.info(format("Caught AccessControlException when accessing system " +
425418
"property [%s]; its value will be returned [null]. Reason: %s",
426-
propertyName, ex.getMessage()));
419+
attributeName, ex.getMessage()));
427420
}
428421
return null;
429422
}

0 commit comments

Comments
 (0)