From 4237ad166c82f2ecb066c462f72a4e7001320460 Mon Sep 17 00:00:00 2001 From: chiba Date: Thu, 2 Nov 2006 06:01:24 +0000 Subject: [PATCH] JIRA JASSIST-28 (including a performance bug) has been fixed. git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@327 30ef5769-5b8d-40dd-aea6-55b5d6557bb3 --- Readme.html | 8 +- .../javassist/util/proxy/ProxyFactory.java | 142 ++++++++++++++++-- 2 files changed, 138 insertions(+), 12 deletions(-) diff --git a/Readme.html b/Readme.html index ff1324cf..ce7eb953 100644 --- a/Readme.html +++ b/Readme.html @@ -285,6 +285,12 @@ see javassist.Dump.

-version 3.3 on August 17, 2006 @@ -698,7 +704,7 @@ Howard Lewis Ship, Richard Jones, Marjan Sterjev, Bruce McDonald, Mark Brennan, Vlad Skarzhevskyy, Brett Randall, Tsuyoshi Murakami, Nathan Meyers, Yoshiyuki Usui Yutaka Sunaga, Arjan van der Meer, Bruce Eckel, Guillaume Pothier, -Kumar Matcha, Andreas Salathe, Renat Zubairov, +Kumar Matcha, Andreas Salathe, Renat Zubairov, Armin Haaf and all other contributors for their contributions.


diff --git a/src/main/javassist/util/proxy/ProxyFactory.java b/src/main/javassist/util/proxy/ProxyFactory.java index 566b809d..f42714d8 100644 --- a/src/main/javassist/util/proxy/ProxyFactory.java +++ b/src/main/javassist/util/proxy/ProxyFactory.java @@ -23,9 +23,11 @@ import java.lang.reflect.Member; import java.lang.reflect.Modifier; import java.security.ProtectionDomain; import java.util.HashMap; +import java.util.WeakHashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; +import java.lang.ref.WeakReference; import javassist.CannotCompileException; import javassist.bytecode.*; @@ -123,6 +125,56 @@ public class ProxyFactory { private static final String HANDLER_SETTER = "setHandler"; private static final String HANDLER_SETTER_TYPE = "(" + HANDLER_TYPE + ")V"; + /** + * If true, a generated proxy class is cached and it will be reused + * when generating the proxy class with the same properties is requested. + * The default value is true. + * + * @since 3.4 + */ + public static boolean useCache = true; + + private static WeakHashMap proxyCache = new WeakHashMap(); + + static class CacheKey { + private String classes; + private MethodFilter filter; + private int hash; + WeakReference proxyClass; + + public CacheKey(Class superClass, Class[] interfaces, MethodFilter f) { + classes = getKey(superClass, interfaces); + hash = classes.hashCode(); + filter = f; + proxyClass = null; + } + + public int hashCode() { return hash; } + + public boolean equals(Object obj) { + if (obj instanceof CacheKey) { + CacheKey target = (CacheKey)obj; + return target.filter == filter && target.classes.equals(classes); + } + else + return false; + } + + static String getKey(Class superClass, Class[] interfaces) { + StringBuffer sbuf = new StringBuffer(); + if (superClass != null) + sbuf.append(superClass.getName()); + sbuf.append(':'); + if (interfaces != null) { + int len = interfaces.length; + for (int i = 0; i < len; i++) + sbuf.append(interfaces[i].getName()).append(','); + } + + return sbuf.toString(); + } + } + /** * Constructs a factory of proxy class. */ @@ -174,21 +226,76 @@ public class ProxyFactory { * Generates a proxy class. */ public Class createClass() { - if (thisClass == null) - try { - ClassFile cf = make(); - ClassLoader cl = getClassLoader(); - if (writeDirectory != null) - FactoryHelper.writeFile(cf, writeDirectory); + if (thisClass == null) { + ClassLoader cl = getClassLoader(); + if (useCache) + createClass2(cl); + else + createClass3(cl); + } - thisClass = FactoryHelper.toClass(cf, cl, getDomain()); - setHandler(); + return thisClass; + } + + private void createClass2(ClassLoader cl) { + CacheKey key = new CacheKey(superClass, interfaces, methodFilter); + synchronized (proxyCache) { + HashMap cacheForTheLoader = (HashMap)proxyCache.get(cl); + if (cacheForTheLoader == null) { + cacheForTheLoader = new HashMap(); + proxyCache.put(cl, cacheForTheLoader); + cacheForTheLoader.put(key, key); } - catch (CannotCompileException e) { - throw new RuntimeException(e.getMessage(), e); + else { + CacheKey found = (CacheKey)cacheForTheLoader.get(key); + if (found == null) + cacheForTheLoader.put(key, key); + else { + key = found; + Class c = isValidEntry(key); // no need to synchronize + if (c != null) { + thisClass = c; + return; + } + } } + } + + synchronized (key) { + Class c = isValidEntry(key); + if (c == null) { + createClass3(cl); + key.proxyClass = new WeakReference(thisClass); + } + else + thisClass = c; + } + } + + private Class isValidEntry(CacheKey key) { + WeakReference ref = key.proxyClass; + if (ref != null) { + Class c = (Class)ref.get(); + if(c != null && getHandler(c) == handler) + return c; + } + + return null; + } + + private void createClass3(ClassLoader cl) { + try { + ClassFile cf = make(); + if (writeDirectory != null) + FactoryHelper.writeFile(cf, writeDirectory); + + thisClass = FactoryHelper.toClass(cf, cl, getDomain()); + setHandler(); + } + catch (CannotCompileException e) { + throw new RuntimeException(e.getMessage(), e); + } - return thisClass; } /** @@ -307,6 +414,19 @@ public class ProxyFactory { } } + static MethodHandler getHandler(Class clazz) { + try { + Field f = clazz.getField(DEFAULT_INTERCEPTOR); + f.setAccessible(true); + MethodHandler h = (MethodHandler)f.get(null); + f.setAccessible(false); + return h; + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + private static int counter = 0; private static synchronized String makeProxyName(String classname) { -- 2.39.5