Browse Source

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(…).
pull/231/head
Oliver Gierke 9 years ago
parent
commit
6e09c09afa
  1. 15
      src/main/java/org/springframework/data/projection/ProxyProjectionFactory.java
  2. 33
      src/main/java/org/springframework/data/projection/SpelAwareProxyProjectionFactory.java

15
src/main/java/org/springframework/data/projection/ProxyProjectionFactory.java

@ -30,6 +30,7 @@ import org.springframework.core.convert.ConversionService; @@ -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 @@ -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 @@ -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);
}

33
src/main/java/org/springframework/data/projection/SpelAwareProxyProjectionFactory.java

@ -28,6 +28,7 @@ import org.springframework.beans.factory.annotation.Value; @@ -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 @@ -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 @@ -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();
}
}

Loading…
Cancel
Save