org.springframework.beans
public class: CachedIntrospectionResults [javadoc |
source]
java.lang.Object
org.springframework.beans.CachedIntrospectionResults
Internal class that caches JavaBeans
java.beans.PropertyDescriptor
information for a Java class. Not intended for direct use by application code.
Necessary for own caching of descriptors within the application's
ClassLoader, rather than rely on the JDK's system-wide BeanInfo cache
(in order to avoid leaks on ClassLoader shutdown).
Information is cached statically, so we don't need to create new
objects of this class for every JavaBean we manipulate. Hence, this class
implements the factory design pattern, using a private constructor and
a static #forClass(Class) factory method to obtain instances.
| Field Summary |
|---|
| static final Set | acceptedClassLoaders | Set of ClassLoaders that this CachedIntrospectionResults class will always
accept classes from, even if the classes do not qualify as cache-safe. |
| static final Map | classCache | Map keyed by class containing CachedIntrospectionResults.
Needs to be a WeakHashMap with WeakReferences as values to allow
for proper garbage collection in case of multiple class loaders. |
| Method from org.springframework.beans.CachedIntrospectionResults Detail: |
public static void acceptClassLoader(ClassLoader classLoader) {
if (classLoader != null) {
acceptedClassLoaders.add(classLoader);
}
}
Accept the given ClassLoader as cache-safe, even if its classes would
not qualify as cache-safe in this CachedIntrospectionResults class.
This configuration method is only relevant in scenarios where the Spring
classes reside in a 'common' ClassLoader (e.g. the system ClassLoader)
whose lifecycle is not coupled to the application. In such a scenario,
CachedIntrospectionResults would by default not cache any of the application's
classes, since they would create a leak in the common ClassLoader.
Any acceptClassLoader call at application startup should
be paired with a #clearClassLoader call at application shutdown. |
public static void clearClassLoader(ClassLoader classLoader) {
if (classLoader == null) {
return;
}
synchronized (classCache) {
for (Iterator it = classCache.keySet().iterator(); it.hasNext();) {
Class beanClass = (Class) it.next();
if (isUnderneathClassLoader(beanClass.getClassLoader(), classLoader)) {
it.remove();
}
}
}
synchronized (acceptedClassLoaders) {
for (Iterator it = acceptedClassLoaders.iterator(); it.hasNext();) {
ClassLoader registeredLoader = (ClassLoader) it.next();
if (isUnderneathClassLoader(registeredLoader, classLoader)) {
it.remove();
}
}
}
}
Clear the introspection cache for the given ClassLoader, removing the
introspection results for all classes underneath that ClassLoader,
and deregistering the ClassLoader (and any of its children) from the
acceptance list. |
static CachedIntrospectionResults forClass(Class beanClass) throws BeansException {
CachedIntrospectionResults results = null;
Object value = classCache.get(beanClass);
if (value instanceof Reference) {
Reference ref = (Reference) value;
results = (CachedIntrospectionResults) ref.get();
}
else {
results = (CachedIntrospectionResults) value;
}
if (results == null) {
// can throw BeansException
results = new CachedIntrospectionResults(beanClass);
if (ClassUtils.isCacheSafe(beanClass, CachedIntrospectionResults.class.getClassLoader()) ||
isClassLoaderAccepted(beanClass.getClassLoader())) {
classCache.put(beanClass, results);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Not strongly caching class [" + beanClass.getName() + "] because it is not cache-safe");
}
classCache.put(beanClass, new WeakReference(results));
}
}
return results;
}
Create CachedIntrospectionResults for the given bean class.
We don't want to use synchronization here. Object references are atomic,
so we can live with doing the occasional unnecessary lookup at startup only. |
Class getBeanClass() {
return this.beanInfo.getBeanDescriptor().getBeanClass();
}
|
BeanInfo getBeanInfo() {
return this.beanInfo;
}
|
PropertyDescriptor getPropertyDescriptor(String propertyName) {
return (PropertyDescriptor) this.propertyDescriptorCache.get(propertyName);
}
|