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:
parent
99e9da1e75
commit
7e6d07afaf
@ -1,5 +1,9 @@
|
||||
package org.jboss.netty.handler.codec.serialization;
|
||||
|
||||
|
||||
/**
|
||||
* please use {@link ClassResolvers} as instance factory
|
||||
*/
|
||||
interface ClassResolver {
|
||||
|
||||
Class<?> resolve(String className) throws ClassNotFoundException;
|
||||
|
@ -1,24 +1,66 @@
|
||||
package org.jboss.netty.handler.codec.serialization;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
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();
|
||||
if (contextClassLoader != null) {
|
||||
return contextClassLoader;
|
||||
}
|
||||
|
||||
return CompactObjectInputStream.class.getClassLoader();
|
||||
return ClassResolvers.class.getClassLoader();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ public class ObjectDecoder extends LengthFieldBasedFrameDecoder {
|
||||
* will be raised.
|
||||
*/
|
||||
public ObjectDecoder(int maxObjectSize) {
|
||||
this(maxObjectSize, ClassResolvers.cachingResolver(null));
|
||||
this(maxObjectSize, ClassResolvers.weakCachingResolver(null));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -104,7 +104,7 @@ public class ObjectDecoderInputStream extends InputStream implements
|
||||
} else {
|
||||
this.in = new DataInputStream(in);
|
||||
}
|
||||
this.classResolver = ClassResolvers.cachingResolver(classLoader);
|
||||
this.classResolver = ClassResolvers.weakCachingResolver(classLoader);
|
||||
this.maxObjectSize = maxObjectSize;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user