DATACMNS-1534 - Cache BeanFactory lookup for EvaluationContextExtension.
We now cache the BeanFactory lookup for EvaluationContextExtension within the ExtensionAwareEvalutationContextProvider to avoid (expensive) repeated context scans when creating the actual EvaluationContext. Original pull request: #395.
This commit is contained in:
committed by
Oliver Drotbohm
parent
1ba8732c0b
commit
29adcfbce5
@@ -29,6 +29,7 @@ import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.data.spel.ExtensionAwareEvaluationContextProvider;
|
||||
import org.springframework.data.spel.spi.EvaluationContextExtension;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.Streamable;
|
||||
@@ -52,11 +53,11 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class ExtensionAwareQueryMethodEvaluationContextProvider implements QueryMethodEvaluationContextProvider {
|
||||
|
||||
private final Lazy<org.springframework.data.spel.ExtensionAwareEvaluationContextProvider> delegate;
|
||||
private final ExtensionAwareEvaluationContextProvider delegate;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExtensionAwareQueryMethodEvaluationContextProvider}.
|
||||
*
|
||||
*
|
||||
* @param beanFactory the {@link ListableBeanFactory} to lookup the {@link EvaluationContextExtension}s from, must not
|
||||
* be {@literal null}.
|
||||
*/
|
||||
@@ -65,37 +66,31 @@ public class ExtensionAwareQueryMethodEvaluationContextProvider implements Query
|
||||
|
||||
Assert.notNull(beanFactory, "ListableBeanFactory must not be null!");
|
||||
|
||||
this.delegate = Lazy.of(() -> {
|
||||
|
||||
org.springframework.data.spel.ExtensionAwareEvaluationContextProvider delegate = new org.springframework.data.spel.ExtensionAwareEvaluationContextProvider(
|
||||
() -> getExtensionsFrom(beanFactory));
|
||||
delegate.setBeanFactory(beanFactory);
|
||||
|
||||
return delegate;
|
||||
});
|
||||
this.delegate = new ExtensionAwareEvaluationContextProvider(Lazy.of(() -> getExtensionsFrom(beanFactory)));
|
||||
this.delegate.setBeanFactory(beanFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExtensionAwareQueryMethodEvaluationContextProvider} using the given
|
||||
* {@link EvaluationContextExtension}s.
|
||||
*
|
||||
*
|
||||
* @param extensions must not be {@literal null}.
|
||||
*/
|
||||
public ExtensionAwareQueryMethodEvaluationContextProvider(List<? extends EvaluationContextExtension> extensions) {
|
||||
|
||||
Assert.notNull(extensions, "EvaluationContextExtensions must not be null!");
|
||||
|
||||
this.delegate = Lazy.of(new org.springframework.data.spel.ExtensionAwareEvaluationContextProvider(extensions));
|
||||
this.delegate = new org.springframework.data.spel.ExtensionAwareEvaluationContextProvider(extensions);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.QueryMethodEvaluationContextProvider#getEvaluationContext(org.springframework.data.repository.query.Parameters, java.lang.Object[])
|
||||
*/
|
||||
@Override
|
||||
public <T extends Parameters<?, ?>> EvaluationContext getEvaluationContext(T parameters, Object[] parameterValues) {
|
||||
|
||||
StandardEvaluationContext evaluationContext = delegate.get().getEvaluationContext(parameterValues);
|
||||
StandardEvaluationContext evaluationContext = delegate.getEvaluationContext(parameterValues);
|
||||
|
||||
evaluationContext.setVariables(collectVariables(parameters, parameterValues));
|
||||
|
||||
@@ -187,7 +182,7 @@ public class ExtensionAwareQueryMethodEvaluationContextProvider implements Query
|
||||
/**
|
||||
* Registers a result mapping for the method with the given name. Invocation results for matching methods will be
|
||||
* piped through the mapping.
|
||||
*
|
||||
*
|
||||
* @param methodName
|
||||
* @param mapping
|
||||
*/
|
||||
@@ -195,7 +190,7 @@ public class ExtensionAwareQueryMethodEvaluationContextProvider implements Query
|
||||
this.directMappings.put(methodName, mapping);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
|
||||
*/
|
||||
|
||||
@@ -25,7 +25,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
@@ -37,6 +36,7 @@ import org.springframework.data.spel.EvaluationContextExtensionInformation.Exten
|
||||
import org.springframework.data.spel.EvaluationContextExtensionInformation.RootObjectInformation;
|
||||
import org.springframework.data.spel.spi.EvaluationContextExtension;
|
||||
import org.springframework.data.spel.spi.Function;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.Optionals;
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
@@ -66,7 +66,7 @@ public class ExtensionAwareEvaluationContextProvider implements EvaluationContex
|
||||
|
||||
private final Map<Class<?>, EvaluationContextExtensionInformation> extensionInformationCache = new ConcurrentHashMap<>();
|
||||
|
||||
private final Supplier<? extends Collection<? extends EvaluationContextExtension>> extensions;
|
||||
private final Lazy<? extends Collection<? extends EvaluationContextExtension>> extensions;
|
||||
private ListableBeanFactory beanFactory;
|
||||
|
||||
ExtensionAwareEvaluationContextProvider() {
|
||||
@@ -81,7 +81,7 @@ public class ExtensionAwareEvaluationContextProvider implements EvaluationContex
|
||||
*/
|
||||
public ExtensionAwareEvaluationContextProvider(ListableBeanFactory beanFactory) {
|
||||
|
||||
this(() -> getExtensionsFrom(beanFactory));
|
||||
this(Lazy.of(() -> getExtensionsFrom(beanFactory)));
|
||||
this.setBeanFactory(beanFactory);
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ public class ExtensionAwareEvaluationContextProvider implements EvaluationContex
|
||||
* @param extensions must not be {@literal null}.
|
||||
*/
|
||||
public ExtensionAwareEvaluationContextProvider(Collection<? extends EvaluationContextExtension> extensions) {
|
||||
this(() -> extensions);
|
||||
this(Lazy.of(extensions));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
package org.springframework.data.repository.query;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@@ -31,10 +34,13 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.spel.ExtensionAwareEvaluationContextProvider;
|
||||
import org.springframework.data.spel.spi.EvaluationContextExtension;
|
||||
import org.springframework.data.spel.spi.Function;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
@@ -279,6 +285,33 @@ public class ExtensionAwareEvaluationContextProviderUnitTests {
|
||||
assertThat(evaluateExpression("methodWithVarArgs('one', 'two')")).isEqualTo("varargs");
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1534
|
||||
public void contextProviderShouldLazilyLookUpExtensions() {
|
||||
|
||||
ListableBeanFactory beanFactory = Mockito.mock(ListableBeanFactory.class);
|
||||
|
||||
ExtensionAwareEvaluationContextProvider contextProvider = new ExtensionAwareEvaluationContextProvider(beanFactory);
|
||||
|
||||
verify(beanFactory, never()).getBeansOfType(eq(EvaluationContextExtension.class), anyBoolean(), anyBoolean());
|
||||
|
||||
contextProvider.getEvaluationContext(null);
|
||||
|
||||
verify(beanFactory).getBeansOfType(eq(EvaluationContextExtension.class), anyBoolean(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1534
|
||||
public void contextProviderShouldLookupExtensionsOnlyOnce() {
|
||||
|
||||
ListableBeanFactory beanFactory = Mockito.mock(ListableBeanFactory.class);
|
||||
|
||||
ExtensionAwareEvaluationContextProvider contextProvider = new ExtensionAwareEvaluationContextProvider(beanFactory);
|
||||
|
||||
contextProvider.getEvaluationContext(null);
|
||||
contextProvider.getEvaluationContext(null);
|
||||
|
||||
verify(beanFactory).getBeansOfType(eq(EvaluationContextExtension.class), anyBoolean(), anyBoolean());
|
||||
}
|
||||
|
||||
private static ExtensionAwareQueryMethodEvaluationContextProvider createContextProviderWithOverloads() {
|
||||
|
||||
return new ExtensionAwareQueryMethodEvaluationContextProvider(Collections.singletonList( //
|
||||
|
||||
Reference in New Issue
Block a user