Browse Source

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
tags/rel_3_17_1_ga
chiba 17 years ago
parent
commit
4237ad166c
2 changed files with 138 additions and 12 deletions
  1. 7
    1
      Readme.html
  2. 131
    11
      src/main/javassist/util/proxy/ProxyFactory.java

+ 7
- 1
Readme.html View File

@@ -285,6 +285,12 @@ see javassist.Dump.
<ul>
<li>A bug in CodeConverter#replaceFieldRead() and CodeConverter#replaceFieldWrite()
was fixed. <a href="http://jira.jboss.com/jira/browse/JBAOP-284">JBAOP-284</a>.

<li>A synchronization bug and a performance bug in <code>javassist.util.proxy</code>
have been fixed
(<a href="http://jira.jboss.com/jira/browse/JASSIST-28">JASSIST-28</a>).
Now generated proxy classes are cached. To turn the caching off,
set <code>ProxyFactory.useCache</code> to <code>false</code>.
</ul>

<p>-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.

<p><br>

+ 131
- 11
src/main/javassist/util/proxy/ProxyFactory.java View File

@@ -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) {

Loading…
Cancel
Save