Additional caching for ResolvableTypes
Add additional caching to ResolvableTypes and SerializableTypeWrapper in order to improve SpEL performance. Issue: SPR-11388
This commit is contained in:
@@ -115,6 +115,12 @@ public final class ResolvableType implements Serializable {
|
||||
*/
|
||||
private final Class<?> resolved;
|
||||
|
||||
private ResolvableType superType;
|
||||
|
||||
private ResolvableType[] interfaces;
|
||||
|
||||
private ResolvableType[] generics;
|
||||
|
||||
|
||||
/**
|
||||
* Private constructor used to create a new {@link ResolvableType} for resolution purposes.
|
||||
@@ -360,7 +366,11 @@ public final class ResolvableType implements Serializable {
|
||||
if (resolved == null || resolved.getGenericSuperclass() == null) {
|
||||
return NONE;
|
||||
}
|
||||
return forType(SerializableTypeWrapper.forGenericSuperclass(resolved), asVariableResolver());
|
||||
if (this.superType == null) {
|
||||
this.superType = forType(SerializableTypeWrapper.forGenericSuperclass(resolved),
|
||||
asVariableResolver());
|
||||
}
|
||||
return this.superType;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -374,7 +384,11 @@ public final class ResolvableType implements Serializable {
|
||||
if (resolved == null || ObjectUtils.isEmpty(resolved.getGenericInterfaces())) {
|
||||
return EMPTY_TYPES_ARRAY;
|
||||
}
|
||||
return forTypes(SerializableTypeWrapper.forGenericInterfaces(resolved), asVariableResolver());
|
||||
if (this.interfaces == null) {
|
||||
this.interfaces = forTypes(SerializableTypeWrapper.forGenericInterfaces(resolved),
|
||||
asVariableResolver());
|
||||
}
|
||||
return this.interfaces;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -551,19 +565,24 @@ public final class ResolvableType implements Serializable {
|
||||
if (this == NONE) {
|
||||
return EMPTY_TYPES_ARRAY;
|
||||
}
|
||||
if (this.type instanceof Class<?>) {
|
||||
Class<?> typeClass = (Class<?>) this.type;
|
||||
return forTypes(SerializableTypeWrapper.forTypeParameters(typeClass), this.variableResolver);
|
||||
}
|
||||
if (this.type instanceof ParameterizedType) {
|
||||
Type[] actualTypeArguments = ((ParameterizedType) this.type).getActualTypeArguments();
|
||||
ResolvableType[] generics = new ResolvableType[actualTypeArguments.length];
|
||||
for (int i = 0; i < actualTypeArguments.length; i++) {
|
||||
generics[i] = forType(actualTypeArguments[i], this.variableResolver);
|
||||
if (this.generics == null) {
|
||||
if (this.type instanceof Class<?>) {
|
||||
Class<?> typeClass = (Class<?>) this.type;
|
||||
this.generics = forTypes(SerializableTypeWrapper.forTypeParameters(typeClass), this.variableResolver);
|
||||
}
|
||||
else if (this.type instanceof ParameterizedType) {
|
||||
Type[] actualTypeArguments = ((ParameterizedType) this.type).getActualTypeArguments();
|
||||
ResolvableType[] generics = new ResolvableType[actualTypeArguments.length];
|
||||
for (int i = 0; i < actualTypeArguments.length; i++) {
|
||||
generics[i] = forType(actualTypeArguments[i], this.variableResolver);
|
||||
}
|
||||
this.generics = generics;
|
||||
}
|
||||
else {
|
||||
this.generics = resolveType().getGenerics();
|
||||
}
|
||||
return generics;
|
||||
}
|
||||
return resolveType().getGenerics();
|
||||
return this.generics;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.lang.reflect.TypeVariable;
|
||||
import java.lang.reflect.WildcardType;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
@@ -63,6 +64,9 @@ abstract class SerializableTypeWrapper {
|
||||
private static final Method GET_TYPE_PROVIDER_METHOD = ReflectionUtils.findMethod(
|
||||
SerializableTypeProxy.class, "getTypeProvider");
|
||||
|
||||
private static final ConcurrentReferenceHashMap<Type, Type> cache =
|
||||
new ConcurrentReferenceHashMap<Type, Type>(256);
|
||||
|
||||
/**
|
||||
* Return a {@link Serializable} variant of {@link Field#getGenericType()}.
|
||||
*/
|
||||
@@ -150,13 +154,19 @@ abstract class SerializableTypeWrapper {
|
||||
if (provider.getType() instanceof Serializable || provider.getType() == null) {
|
||||
return provider.getType();
|
||||
}
|
||||
Type cached = cache.get(provider.getType());
|
||||
if(cached != null) {
|
||||
return cached;
|
||||
}
|
||||
for (Class<?> type : SUPPORTED_SERIALIZABLE_TYPES) {
|
||||
if (type.isAssignableFrom(provider.getType().getClass())) {
|
||||
ClassLoader classLoader = provider.getClass().getClassLoader();
|
||||
Class<?>[] interfaces = new Class<?>[] { type,
|
||||
SerializableTypeProxy.class, Serializable.class };
|
||||
InvocationHandler handler = new TypeProxyInvocationHandler(provider);
|
||||
return (Type) Proxy.newProxyInstance(classLoader, interfaces, handler);
|
||||
cached = (Type) Proxy.newProxyInstance(classLoader, interfaces, handler);
|
||||
cache.put(provider.getType(), cached);
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unsupported Type class " + provider.getType().getClass().getName());
|
||||
|
||||
Reference in New Issue
Block a user