|
|
|
@ -52,6 +52,18 @@ import org.springframework.util.StringUtils;
@@ -52,6 +52,18 @@ import org.springframework.util.StringUtils;
|
|
|
|
|
* implements the factory design pattern, using a private constructor and |
|
|
|
|
* a static {@link #forClass(Class)} factory method to obtain instances. |
|
|
|
|
* |
|
|
|
|
* <p>Note that for caching to work effectively, some preconditions need to be met: |
|
|
|
|
* Prefer an arrangement where the Spring jars live in the same ClassLoader as the |
|
|
|
|
* application classes, which allows for clean caching along with the application's |
|
|
|
|
* lifecycle in any case. For a web application, consider declaring a local |
|
|
|
|
* {@link org.springframework.web.util.IntrospectorCleanupListener} in {@code web.xml} |
|
|
|
|
* in case of a multi-ClassLoader layout, which will allow for effective caching as well. |
|
|
|
|
* |
|
|
|
|
* <p>In case of a non-clean ClassLoader arrangement without a cleanup listener having |
|
|
|
|
* been set up, this class will fall back to a weak-reference-based caching model that |
|
|
|
|
* recreates much-requested entries every time the garbage collector removed them. In |
|
|
|
|
* such a scenario, consider the {@link #IGNORE_BEANINFO_PROPERTY_NAME} system property. |
|
|
|
|
* |
|
|
|
|
* @author Rod Johnson |
|
|
|
|
* @author Juergen Hoeller |
|
|
|
|
* @since 05 May 2001 |
|
|
|
@ -61,11 +73,33 @@ import org.springframework.util.StringUtils;
@@ -61,11 +73,33 @@ import org.springframework.util.StringUtils;
|
|
|
|
|
*/ |
|
|
|
|
public class CachedIntrospectionResults { |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* System property that instructs Spring to use the {@link Introspector#IGNORE_ALL_BEANINFO} |
|
|
|
|
* mode when calling the JavaBeans {@link Introspector}: "spring.beaninfo.ignore", with a |
|
|
|
|
* value of "true" skipping the search for {@code BeanInfo} classes (typically for scenarios |
|
|
|
|
* where no such classes are being defined for beans in the application in the first place). |
|
|
|
|
* <p>Default is "false", considering all {@code BeanInfo} metadata classes, like for |
|
|
|
|
* standard {@link Introspector#getBeanInfo(Class)} calls. Consider switching this flag to |
|
|
|
|
* "true" if you experience repeated ClassLoader access for non-existing {@code BeanInfo} |
|
|
|
|
* classes, in case such access is expensive on startup or on lazy loading. |
|
|
|
|
* <p>Note that such an effect may also indicate a scenario where caching doesn't work |
|
|
|
|
* effectively: Prefer an arrangement where the Spring jars live in the same ClassLoader |
|
|
|
|
* as the application classes, which allows for clean caching along with the application's |
|
|
|
|
* lifecycle in any case. For a web application, consider declaring a local |
|
|
|
|
* {@link org.springframework.web.util.IntrospectorCleanupListener} in {@code web.xml} |
|
|
|
|
* in case of a multi-ClassLoader layout, which will allow for effective caching as well. |
|
|
|
|
* @see Introspector#getBeanInfo(Class, int) |
|
|
|
|
*/ |
|
|
|
|
public static final String IGNORE_BEANINFO_PROPERTY_NAME = "spring.beaninfo.ignore"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static final Log logger = LogFactory.getLog(CachedIntrospectionResults.class); |
|
|
|
|
|
|
|
|
|
private static final boolean shouldIntrospectorIgnoreBeaninfoClasses; |
|
|
|
|
|
|
|
|
|
/** Stores the BeanInfoFactory instances */ |
|
|
|
|
private static List<BeanInfoFactory> beanInfoFactories = |
|
|
|
|
SpringFactoriesLoader.loadFactories(BeanInfoFactory.class, CachedIntrospectionResults.class.getClassLoader()); |
|
|
|
|
private static List<BeanInfoFactory> beanInfoFactories = SpringFactoriesLoader.loadFactories( |
|
|
|
|
BeanInfoFactory.class, CachedIntrospectionResults.class.getClassLoader()); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Set of ClassLoaders that this CachedIntrospectionResults class will always |
|
|
|
@ -81,6 +115,21 @@ public class CachedIntrospectionResults {
@@ -81,6 +115,21 @@ public class CachedIntrospectionResults {
|
|
|
|
|
static final Map<Class<?>, Object> classCache = new WeakHashMap<Class<?>, Object>(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static { |
|
|
|
|
boolean ignoreValue; |
|
|
|
|
try { |
|
|
|
|
ignoreValue = "true".equalsIgnoreCase(System.getProperty(IGNORE_BEANINFO_PROPERTY_NAME)); |
|
|
|
|
} |
|
|
|
|
catch (Throwable ex) { |
|
|
|
|
if (logger.isDebugEnabled()) { |
|
|
|
|
logger.debug("Could not obtain system property '" + IGNORE_BEANINFO_PROPERTY_NAME + "': " + ex); |
|
|
|
|
} |
|
|
|
|
ignoreValue = false; |
|
|
|
|
} |
|
|
|
|
shouldIntrospectorIgnoreBeaninfoClasses = ignoreValue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Accept the given ClassLoader as cache-safe, even if its classes would |
|
|
|
|
* not qualify as cache-safe in this CachedIntrospectionResults class. |
|
|
|
@ -243,7 +292,9 @@ public class CachedIntrospectionResults {
@@ -243,7 +292,9 @@ public class CachedIntrospectionResults {
|
|
|
|
|
} |
|
|
|
|
if (beanInfo == null) { |
|
|
|
|
// If none of the factories supported the class, fall back to the default
|
|
|
|
|
beanInfo = Introspector.getBeanInfo(beanClass); |
|
|
|
|
beanInfo = (shouldIntrospectorIgnoreBeaninfoClasses ? |
|
|
|
|
Introspector.getBeanInfo(beanClass, Introspector.IGNORE_ALL_BEANINFO) : |
|
|
|
|
Introspector.getBeanInfo(beanClass)); |
|
|
|
|
} |
|
|
|
|
this.beanInfo = beanInfo; |
|
|
|
|
|
|
|
|
|