DATACMNS-1107 - ProxyProjectionFactory now caches ProjectionInformation instances.
To avoid the repeated scanning of projection interfaces for property descriptors we now cache the ProjectionInformation instances created via ProjectionFactory.getProjectionInformation(…). Adapted SpelAwareProxyProjectionFactory to now apply its customizations in newly introduced createProjectionInformation(…).
This commit is contained in:
@@ -30,6 +30,7 @@ import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||
|
||||
/**
|
||||
* A {@link ProjectionFactory} to create JDK proxies to back interfaces and handle method invocations on them. By
|
||||
@@ -46,6 +47,7 @@ class ProxyProjectionFactory implements ProjectionFactory, BeanClassLoaderAware
|
||||
|
||||
private final List<MethodInterceptorFactory> factories;
|
||||
private final ConversionService conversionService;
|
||||
private final Map<Class<?>, ProjectionInformation> projectionInformationCache = new ConcurrentReferenceHashMap<>();
|
||||
private ClassLoader classLoader;
|
||||
|
||||
/**
|
||||
@@ -127,7 +129,18 @@ class ProxyProjectionFactory implements ProjectionFactory, BeanClassLoaderAware
|
||||
* @see org.springframework.data.projection.ProjectionFactory#getProjectionInformation(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public ProjectionInformation getProjectionInformation(Class<?> projectionType) {
|
||||
public final ProjectionInformation getProjectionInformation(Class<?> projectionType) {
|
||||
|
||||
return projectionInformationCache.computeIfAbsent(projectionType, this::createProjectionInformation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fresh, cacheable {@link ProjectionInformation} instance for the given projection type.
|
||||
*
|
||||
* @param projectionType must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected ProjectionInformation createProjectionInformation(Class<?> projectionType) {
|
||||
return new DefaultProjectionInformation(projectionType);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.util.AnnotationDetectionMethodCallback;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
@@ -68,25 +69,17 @@ public class SpelAwareProxyProjectionFactory extends ProxyProjectionFactory impl
|
||||
protected MethodInterceptor postProcessAccessorInterceptor(MethodInterceptor interceptor, Object source,
|
||||
Class<?> projectionType) {
|
||||
|
||||
if (!typeCache.containsKey(projectionType)) {
|
||||
|
||||
AnnotationDetectionMethodCallback<Value> callback = new AnnotationDetectionMethodCallback<>(Value.class);
|
||||
ReflectionUtils.doWithMethods(projectionType, callback);
|
||||
|
||||
typeCache.put(projectionType, callback.hasFoundAnnotation());
|
||||
}
|
||||
|
||||
return typeCache.get(projectionType)
|
||||
return typeCache.computeIfAbsent(projectionType, SpelAwareProxyProjectionFactory::hasMethodWithValueAnnotation)
|
||||
? new SpelEvaluatingMethodInterceptor(interceptor, source, beanFactory, parser, projectionType)
|
||||
: interceptor;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.projection.ProxyProjectionFactory#getProjectionInformation(java.lang.Class)
|
||||
* @see org.springframework.data.projection.ProxyProjectionFactory#createProjectionInformation(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public ProjectionInformation getProjectionInformation(Class<?> projectionType) {
|
||||
protected ProjectionInformation createProjectionInformation(Class<?> projectionType) {
|
||||
|
||||
return new DefaultProjectionInformation(projectionType) {
|
||||
|
||||
@@ -111,4 +104,20 @@ public class SpelAwareProxyProjectionFactory extends ProxyProjectionFactory impl
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given type as a method annotated with {@link Value}.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private static boolean hasMethodWithValueAnnotation(Class<?> type) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
|
||||
AnnotationDetectionMethodCallback<Value> callback = new AnnotationDetectionMethodCallback<>(Value.class);
|
||||
ReflectionUtils.doWithMethods(type, callback);
|
||||
|
||||
return callback.hasFoundAnnotation();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user