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;
|
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;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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