From e32f6f133741ecd8eb99633eb239bc9d0ed99e69 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Mon, 1 Jun 2009 23:29:51 +0000 Subject: [PATCH] OPENJPA-1113 - Cache Reflection artifacts for performance improvement. git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@780881 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/openjpa/enhance/Reflection.java | 108 ++++++++++++++++-- .../openjpa/kernel/AbstractBrokerFactory.java | 15 +-- 2 files changed, 108 insertions(+), 15 deletions(-) diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java index 8023ab98b..f56652b8c 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java @@ -21,20 +21,24 @@ package org.apache.openjpa.enhance; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.security.AccessController; +import java.util.Collection; import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; import java.util.Set; import java.util.TreeSet; +import java.util.WeakHashMap; import org.apache.commons.lang.StringUtils; import org.apache.openjpa.lib.util.J2DoPrivHelper; import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.lib.util.Reflectable; -import org.apache.openjpa.util.GeneralException; -import org.apache.openjpa.util.UserException; +import org.apache.openjpa.util.GeneralException; +import org.apache.openjpa.util.UserException; /** * Reflection utilities used to support and augment enhancement. Used both @@ -47,14 +51,89 @@ public class Reflection { private static final Localizer _loc = Localizer.forPackage (Reflection.class); + // Weak HashMap caches of getter/setter/beanProperty methods + private static Map, Map> getterMethodCache = + new WeakHashMap, Map>(); + private static Map, Map> setterMethodCache = + new WeakHashMap, Map>(); + private static Map, Set> beanPropertiesNameCache = + new WeakHashMap, Set>(); + + private static Method getGetterMethod(Class cls, String prop) { + Method rtnMethod = null; + Map clsMap = getterMethodCache.get(cls); + if (clsMap != null) { + rtnMethod = clsMap.get(prop); + } + return rtnMethod; + } + + private static void setGetterMethod(Class cls, String prop, + Method method) { + Map clsMap = getterMethodCache.get(cls); + if (clsMap == null) { + clsMap = new HashMap(); + getterMethodCache.put(cls, clsMap); + } + clsMap.put(prop, method); + } + + private static Method getSetterMethod(Class cls, String prop) { + Method rtnMethod = null; + Map clsMap = setterMethodCache.get(cls); + if (clsMap != null) { + rtnMethod = clsMap.get(prop); + } + return rtnMethod; + } + + private static void setSetterMethod(Class cls, String prop, + Method method) { + Map clsMap = setterMethodCache.get(cls); + if (clsMap == null) { + clsMap = new HashMap(); + setterMethodCache.put(cls, clsMap); + } + clsMap.put(prop, method); + } + + public static void flushCaches() { + getterMethodCache.clear(); + setterMethodCache.clear(); + beanPropertiesNameCache.clear(); + } + + public static void flushCaches(Collection loaders) { + if (loaders.size() > 0) { + flushCache(loaders, getterMethodCache); + flushCache(loaders, setterMethodCache); + flushCache(loaders, beanPropertiesNameCache); + } + } + + private static void flushCache(Collection loaders, + Map, ?> cache) { + for (Iterator> itr = cache.keySet().iterator(); + itr.hasNext();) { + Class cls = itr.next(); + ClassLoader sLoader = cls.getClassLoader(); + if (loaders.contains(sLoader)) { + itr.remove(); + } + } + } + /** * Return the getter method matching the given property name, optionally * throwing an exception if none. */ public static Method findGetter(Class cls, String prop, boolean mustExist) { + Method m = getGetterMethod(cls, prop); + if (m != null) { + return m; + } prop = StringUtils.capitalize(prop); String name = "get" + prop; - Method m; try { // this algorithm searches for a get or is method in // a breadth-first manner. @@ -62,12 +141,15 @@ public class Reflection { c = c.getSuperclass()) { m = getDeclaredMethod(c, name, null); if (m != null) { + setGetterMethod(cls, prop, m); return m; } else { m = getDeclaredMethod(c, "is" + prop, null); if (m != null && (m.getReturnType() == boolean.class - || m.getReturnType() == Boolean.class)) + || m.getReturnType() == Boolean.class)) { + setGetterMethod(cls, prop, m); return m; + } } } } catch (Exception e) { @@ -95,14 +177,19 @@ public class Reflection { */ public static Method findSetter(Class cls, String prop, Class param, boolean mustExist) { + Method m = getSetterMethod(cls, prop); + if (m != null) { + return m; + } String name = "set" + StringUtils.capitalize(prop); - Method m; try { for (Class c = cls; c != null && c != Object.class; c = c.getSuperclass()) { m = getDeclaredMethod(c, name, param); - if (m != null) + if (m != null) { + setSetterMethod(cls, prop, m); return m; + } } } catch (Exception e) { throw new GeneralException(e); @@ -774,10 +861,14 @@ public class Reflection { public static Set getBeanStylePropertyNames(Class c) { if (c == null) return Collections.EMPTY_SET; + Set result = beanPropertiesNameCache.get(c); + if (result != null) { + return result; + } Method[] methods = c.getMethods(); if (methods == null || methods.length < 2) return Collections.EMPTY_SET; - Set result = new TreeSet(); + /*Set*/ result = new TreeSet(); for (Method m : methods) { if (m.getName().startsWith("get")) { if (!canReflect(m)) @@ -795,6 +886,7 @@ public class Reflection { } } } + beanPropertiesNameCache.put(c, result); return result; } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java index 0f241939f..9d6399c4f 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java @@ -31,23 +31,26 @@ import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; import javax.transaction.Status; import javax.transaction.Synchronization; import javax.transaction.Transaction; import javax.transaction.TransactionManager; -import org.apache.commons.lang.StringUtils; import org.apache.commons.collections.set.MapBackedSet; -import org.apache.openjpa.conf.OpenJPAConfiguration; -import org.apache.openjpa.conf.OpenJPAVersion; +import org.apache.commons.lang.StringUtils; import org.apache.openjpa.conf.BrokerValue; +import org.apache.openjpa.conf.OpenJPAConfiguration; import org.apache.openjpa.conf.OpenJPAConfigurationImpl; +import org.apache.openjpa.conf.OpenJPAVersion; import org.apache.openjpa.datacache.DataCacheStoreManager; import org.apache.openjpa.ee.ManagedRuntime; +import org.apache.openjpa.enhance.ManagedClassSubclasser; import org.apache.openjpa.enhance.PCRegistry; import org.apache.openjpa.enhance.PersistenceCapable; -import org.apache.openjpa.enhance.ManagedClassSubclasser; +import org.apache.openjpa.enhance.Reflection; import org.apache.openjpa.event.BrokerFactoryEvent; import org.apache.openjpa.event.RemoteCommitEventManager; import org.apache.openjpa.lib.conf.Configuration; @@ -55,9 +58,7 @@ import org.apache.openjpa.lib.conf.Configurations; import org.apache.openjpa.lib.log.Log; import org.apache.openjpa.lib.util.J2DoPrivHelper; import org.apache.openjpa.lib.util.Localizer; -import java.util.concurrent.ConcurrentHashMap; import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashSet; -import java.util.concurrent.locks.ReentrantLock; import org.apache.openjpa.meta.MetaDataRepository; import org.apache.openjpa.util.GeneralException; import org.apache.openjpa.util.InvalidStateException; @@ -410,7 +411,7 @@ public abstract class AbstractBrokerFactory PCRegistry.removeRegisterClassListener (_conf.getMetaDataRepositoryInstance()); } - + Reflection.flushCaches(_pcClassLoaders); _conf.close(); _closed = true; Log log = _conf.getLog(OpenJPAConfiguration.LOG_RUNTIME);