use weak cache as default cache - it doesn't break class unloading

providing multiple implementations for caching, each good for its own specific use-case
This commit is contained in:
alepar 2011-11-22 18:16:30 +04:00
parent 99e9da1e75
commit 7e6d07afaf
7 changed files with 179 additions and 10 deletions

View File

@ -1,5 +1,9 @@
package org.jboss.netty.handler.codec.serialization; package org.jboss.netty.handler.codec.serialization;
/**
* please use {@link ClassResolvers} as instance factory
*/
interface ClassResolver { interface ClassResolver {
Class<?> resolve(String className) throws ClassNotFoundException; Class<?> resolve(String className) throws ClassNotFoundException;

View File

@ -1,24 +1,66 @@
package org.jboss.netty.handler.codec.serialization; package org.jboss.netty.handler.codec.serialization;
import java.lang.ref.Reference;
import java.util.HashMap; import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
public class ClassResolvers { public class ClassResolvers {
public static ClassResolver cachingResolver(ClassLoader classLoader) {
if (classLoader == null) {
classLoader = defaultClassLoader();
}
return new CachingClassResolver(new ClassloaderClassResolver(classLoader), new HashMap<String, Class<?>>()); /**
* non-agressive non-concurrent cache
* good for non-shared default cache
*
* @param classLoader - specific classLoader to use, or null if you want to revert to default
* @return new instance of class resolver
*/
public static ClassResolver weakCachingResolver(ClassLoader classLoader) {
return new CachingClassResolver(new ClassloaderClassResolver(defaultClassLoader(classLoader)), new WeakReferenceMap<String, Class<?>>(new HashMap<String, Reference<Class<?>>>()));
} }
static ClassLoader defaultClassLoader() { /**
* agressive non-concurrent cache
* good for non-shared cache, when we're not worried about class unloading
*
* @param classLoader - specific classLoader to use, or null if you want to revert to default
* @return new instance of class resolver
*/
public static ClassResolver softCachingResolver(ClassLoader classLoader) {
return new CachingClassResolver(new ClassloaderClassResolver(defaultClassLoader(classLoader)), new SoftReferenceMap<String, Class<?>>(new HashMap<String, Reference<Class<?>>>()));
}
/**
* non-agressive concurrent cache
* good for shared cache, when we're worried about class unloading
*
* @param classLoader - specific classLoader to use, or null if you want to revert to default
* @return new instance of class resolver
*/
public static ClassResolver weakCachingConcurrentResolver(ClassLoader classLoader) {
return new CachingClassResolver(new ClassloaderClassResolver(defaultClassLoader(classLoader)), new WeakReferenceMap<String, Class<?>>(new ConcurrentHashMap<String, Reference<Class<?>>>()));
}
/**
* agressive concurrent cache
* good for shared cache, when we're not worried about class unloading
*
* @param classLoader - specific classLoader to use, or null if you want to revert to default
* @return new instance of class resolver
*/
public static ClassResolver softCachingConcurrentResolver(ClassLoader classLoader) {
return new CachingClassResolver(new ClassloaderClassResolver(defaultClassLoader(classLoader)), new SoftReferenceMap<String, Class<?>>(new ConcurrentHashMap<String, Reference<Class<?>>>()));
}
static ClassLoader defaultClassLoader(ClassLoader classLoader) {
if (classLoader != null) {
return classLoader;
}
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
if (contextClassLoader != null) { if (contextClassLoader != null) {
return contextClassLoader; return contextClassLoader;
} }
return CompactObjectInputStream.class.getClassLoader(); return ClassResolvers.class.getClassLoader();
} }
} }

View File

@ -64,7 +64,7 @@ public class ObjectDecoder extends LengthFieldBasedFrameDecoder {
* will be raised. * will be raised.
*/ */
public ObjectDecoder(int maxObjectSize) { public ObjectDecoder(int maxObjectSize) {
this(maxObjectSize, ClassResolvers.cachingResolver(null)); this(maxObjectSize, ClassResolvers.weakCachingResolver(null));
} }
/** /**

View File

@ -104,7 +104,7 @@ public class ObjectDecoderInputStream extends InputStream implements
} else { } else {
this.in = new DataInputStream(in); this.in = new DataInputStream(in);
} }
this.classResolver = ClassResolvers.cachingResolver(classLoader); this.classResolver = ClassResolvers.weakCachingResolver(classLoader);
this.maxObjectSize = maxObjectSize; this.maxObjectSize = maxObjectSize;
} }

View File

@ -0,0 +1,87 @@
package org.jboss.netty.handler.codec.serialization;
import java.lang.ref.Reference;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
abstract class ReferenceMap<K, V> implements Map<K, V> {
private final Map<K, Reference<V>> delegate;
protected ReferenceMap(Map<K, Reference<V>> delegate) {
this.delegate = delegate;
}
abstract Reference<V> fold(V value);
private V unfold(Reference<V> ref) {
if (ref == null) {
return null;
}
return ref.get();
}
@Override
public int size() {
return delegate.size();
}
@Override
public boolean isEmpty() {
return delegate.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return delegate.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
throw new UnsupportedOperationException();
}
@Override
public V get(Object key) {
return unfold(delegate.get(key));
}
@Override
public V put(K key, V value) {
return unfold(delegate.put(key, fold(value)));
}
@Override
public V remove(Object key) {
return unfold(delegate.remove(key));
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
for (Entry<? extends K, ? extends V> entry : m.entrySet()) {
delegate.put(entry.getKey(), fold(entry.getValue()));
}
}
@Override
public void clear() {
delegate.clear();
}
@Override
public Set<K> keySet() {
return delegate.keySet();
}
@Override
public Collection<V> values() {
throw new UnsupportedOperationException();
}
@Override
public Set<Entry<K, V>> entrySet() {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,18 @@
package org.jboss.netty.handler.codec.serialization;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.util.Map;
public class SoftReferenceMap<K, V> extends ReferenceMap<K, V> {
public SoftReferenceMap(Map<K, Reference<V>> delegate) {
super(delegate);
}
@Override
Reference<V> fold(V value) {
return new SoftReference<V>(value);
}
}

View File

@ -0,0 +1,18 @@
package org.jboss.netty.handler.codec.serialization;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.Map;
public class WeakReferenceMap<K, V> extends ReferenceMap<K, V> {
public WeakReferenceMap(Map<K, Reference<V>> delegate) {
super(delegate);
}
@Override
Reference<V> fold(V value) {
return new WeakReference<V>(value);
}
}