Merge branch '6.2.x'
This commit is contained in:
commit
56269d76e5
|
@ -514,8 +514,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
|||
* to check whether the bean with the given name matches the specified type. Allow
|
||||
* additional constraints to be applied to ensure that beans are not created early.
|
||||
* @param name the name of the bean to query
|
||||
* @param typeToMatch the type to match against (as a
|
||||
* {@code ResolvableType})
|
||||
* @param typeToMatch the type to match against (as a {@code ResolvableType})
|
||||
* @return {@code true} if the bean type matches, {@code false} if it
|
||||
* doesn't match or cannot be determined yet
|
||||
* @throws NoSuchBeanDefinitionException if there is no bean with the given name
|
||||
|
|
|
@ -60,6 +60,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
|
|||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
|
||||
import org.springframework.beans.factory.CannotLoadBeanClassException;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InjectionPoint;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||
|
@ -191,8 +192,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
/** Map from bean name to merged BeanDefinitionHolder. */
|
||||
private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256);
|
||||
|
||||
/** Set of bean definition names with a primary marker. */
|
||||
private final Set<String> primaryBeanNames = ConcurrentHashMap.newKeySet(16);
|
||||
/** Map of bean definition names with a primary marker plus corresponding type. */
|
||||
private final Map<String, Class<?>> primaryBeanNamesWithType = new ConcurrentHashMap<>(16);
|
||||
|
||||
/** Map of singleton and non-singleton bean names, keyed by dependency type. */
|
||||
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
|
||||
|
@ -1024,7 +1025,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
protected void cacheMergedBeanDefinition(RootBeanDefinition mbd, String beanName) {
|
||||
super.cacheMergedBeanDefinition(mbd, beanName);
|
||||
if (mbd.isPrimary()) {
|
||||
this.primaryBeanNames.add(beanName);
|
||||
this.primaryBeanNamesWithType.put(beanName, Void.class);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1309,7 +1310,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
|
||||
// Cache a primary marker for the given bean.
|
||||
if (beanDefinition.isPrimary()) {
|
||||
this.primaryBeanNames.add(beanName);
|
||||
this.primaryBeanNamesWithType.put(beanName, Void.class);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1401,7 +1402,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
destroySingleton(beanName);
|
||||
|
||||
// Remove a cached primary marker for the given bean.
|
||||
this.primaryBeanNames.remove(beanName);
|
||||
this.primaryBeanNamesWithType.remove(beanName);
|
||||
|
||||
// Notify all post-processors that the specified bean definition has been reset.
|
||||
for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {
|
||||
|
@ -1454,9 +1455,18 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
@Override
|
||||
protected void addSingleton(String beanName, Object singletonObject) {
|
||||
super.addSingleton(beanName, singletonObject);
|
||||
|
||||
Predicate<Class<?>> filter = (beanType -> beanType != Object.class && beanType.isInstance(singletonObject));
|
||||
this.allBeanNamesByType.keySet().removeIf(filter);
|
||||
this.singletonBeanNamesByType.keySet().removeIf(filter);
|
||||
|
||||
if (this.primaryBeanNamesWithType.containsKey(beanName) && singletonObject.getClass() != NullBean.class) {
|
||||
Class<?> beanType = (singletonObject instanceof FactoryBean<?> fb ?
|
||||
getTypeForFactoryBean(fb) : singletonObject.getClass());
|
||||
if (beanType != null) {
|
||||
this.primaryBeanNamesWithType.put(beanName, beanType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2245,8 +2255,12 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
* not matching the given bean name.
|
||||
*/
|
||||
private boolean hasPrimaryConflict(String beanName, Class<?> dependencyType) {
|
||||
for (String candidate : this.primaryBeanNames) {
|
||||
if (isTypeMatch(candidate, dependencyType) && !candidate.equals(beanName)) {
|
||||
for (Map.Entry<String, Class<?>> candidate : this.primaryBeanNamesWithType.entrySet()) {
|
||||
String candidateName = candidate.getKey();
|
||||
Class<?> candidateType = candidate.getValue();
|
||||
if (!candidateName.equals(beanName) && (candidateType != Void.class ?
|
||||
dependencyType.isAssignableFrom(candidateType) : // cached singleton class for primary bean
|
||||
isTypeMatch(candidateName, dependencyType))) { // not instantiated yet or not a singleton
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,12 +60,6 @@ class CacheOperationExpressionEvaluatorTests {
|
|||
private final AnnotationCacheOperationSource source = new AnnotationCacheOperationSource();
|
||||
|
||||
|
||||
private Collection<CacheOperation> getOps(String name) {
|
||||
Method method = ReflectionUtils.findMethod(AnnotatedClass.class, name, Object.class, Object.class);
|
||||
return this.source.getCacheOperations(method, AnnotatedClass.class);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testMultipleCachingSource() {
|
||||
Collection<CacheOperation> ops = getOps("multipleCaching");
|
||||
|
@ -144,6 +138,12 @@ class CacheOperationExpressionEvaluatorTests {
|
|||
assertThat(value).isEqualTo(String.class.getName());
|
||||
}
|
||||
|
||||
|
||||
private Collection<CacheOperation> getOps(String name) {
|
||||
Method method = ReflectionUtils.findMethod(AnnotatedClass.class, name, Object.class, Object.class);
|
||||
return this.source.getCacheOperations(method, AnnotatedClass.class);
|
||||
}
|
||||
|
||||
private EvaluationContext createEvaluationContext(Object result) {
|
||||
return createEvaluationContext(result, null);
|
||||
}
|
||||
|
|
|
@ -104,6 +104,7 @@ class CachePutEvaluationTests {
|
|||
assertThat(this.cache.get(anotherValue + 100).get()).as("Wrong value for @CachePut key").isEqualTo(anotherValue);
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
static class Config implements CachingConfigurer {
|
||||
|
@ -121,8 +122,10 @@ class CachePutEvaluationTests {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@CacheConfig("test")
|
||||
public static class SimpleService {
|
||||
|
||||
private AtomicLong counter = new AtomicLong();
|
||||
|
||||
/**
|
||||
|
@ -144,4 +147,5 @@ class CachePutEvaluationTests {
|
|||
return this.counter.getAndIncrement();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -122,34 +122,72 @@ public class StandardEvaluationContext implements EvaluationContext {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify the default root context object (including a type descriptor)
|
||||
* against which unqualified properties, methods, etc. should be resolved.
|
||||
* @param rootObject the root object to use
|
||||
* @param typeDescriptor a corresponding type descriptor
|
||||
*/
|
||||
public void setRootObject(@Nullable Object rootObject, TypeDescriptor typeDescriptor) {
|
||||
this.rootObject = new TypedValue(rootObject, typeDescriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the default root context object against which unqualified
|
||||
* properties, methods, etc. should be resolved.
|
||||
* @param rootObject the root object to use
|
||||
*/
|
||||
public void setRootObject(@Nullable Object rootObject) {
|
||||
this.rootObject = (rootObject != null ? new TypedValue(rootObject) : TypedValue.NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configured default root context object against which unqualified
|
||||
* properties, methods, etc. should be resolved (can be {@link TypedValue#NULL}).
|
||||
*/
|
||||
@Override
|
||||
public TypedValue getRootObject() {
|
||||
return this.rootObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the list of property accessors to use in this evaluation context.
|
||||
* <p>Replaces any previously configured property accessors.
|
||||
*/
|
||||
public void setPropertyAccessors(List<PropertyAccessor> propertyAccessors) {
|
||||
this.propertyAccessors = propertyAccessors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of property accessors configured in this evaluation context.
|
||||
*/
|
||||
@Override
|
||||
public List<PropertyAccessor> getPropertyAccessors() {
|
||||
return initPropertyAccessors();
|
||||
}
|
||||
|
||||
public void addPropertyAccessor(PropertyAccessor accessor) {
|
||||
addBeforeDefault(initPropertyAccessors(), accessor);
|
||||
/**
|
||||
* Add the supplied property accessor to this evaluation context.
|
||||
* @param propertyAccessor the property accessor to add
|
||||
* @see #getPropertyAccessors()
|
||||
* @see #setPropertyAccessors(List)
|
||||
* @see #removePropertyAccessor(PropertyAccessor)
|
||||
*/
|
||||
public void addPropertyAccessor(PropertyAccessor propertyAccessor) {
|
||||
addBeforeDefault(initPropertyAccessors(), propertyAccessor);
|
||||
}
|
||||
|
||||
public boolean removePropertyAccessor(PropertyAccessor accessor) {
|
||||
return initPropertyAccessors().remove(accessor);
|
||||
/**
|
||||
* Remove the supplied property accessor from this evaluation context.
|
||||
* @param propertyAccessor the property accessor to remove
|
||||
* @return {@code true} if the property accessor was removed, {@code false}
|
||||
* if the property accessor was not configured in this evaluation context
|
||||
* @see #getPropertyAccessors()
|
||||
* @see #setPropertyAccessors(List)
|
||||
* @see #addPropertyAccessor(PropertyAccessor)
|
||||
*/
|
||||
public boolean removePropertyAccessor(PropertyAccessor propertyAccessor) {
|
||||
return initPropertyAccessors().remove(propertyAccessor);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -191,8 +229,8 @@ public class StandardEvaluationContext implements EvaluationContext {
|
|||
/**
|
||||
* Remove the supplied index accessor from this evaluation context.
|
||||
* @param indexAccessor the index accessor to remove
|
||||
* @return {@code true} if the index accessor was removed, {@code false} if
|
||||
* the index accessor was not configured in this evaluation context
|
||||
* @return {@code true} if the index accessor was removed, {@code false}
|
||||
* if the index accessor was not configured in this evaluation context
|
||||
* @since 6.2
|
||||
* @see #getIndexAccessors()
|
||||
* @see #setIndexAccessors(List)
|
||||
|
@ -202,44 +240,96 @@ public class StandardEvaluationContext implements EvaluationContext {
|
|||
return initIndexAccessors().remove(indexAccessor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the list of constructor resolvers to use in this evaluation context.
|
||||
* <p>Replaces any previously configured constructor resolvers.
|
||||
*/
|
||||
public void setConstructorResolvers(List<ConstructorResolver> constructorResolvers) {
|
||||
this.constructorResolvers = constructorResolvers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of constructor resolvers to use in this evaluation context.
|
||||
*/
|
||||
@Override
|
||||
public List<ConstructorResolver> getConstructorResolvers() {
|
||||
return initConstructorResolvers();
|
||||
}
|
||||
|
||||
public void addConstructorResolver(ConstructorResolver resolver) {
|
||||
addBeforeDefault(initConstructorResolvers(), resolver);
|
||||
/**
|
||||
* Add the supplied constructor resolver to this evaluation context.
|
||||
* @param constructorResolver the constructor resolver to add
|
||||
* @see #getConstructorResolvers()
|
||||
* @see #setConstructorResolvers(List)
|
||||
* @see #removeConstructorResolver(ConstructorResolver)
|
||||
*/
|
||||
public void addConstructorResolver(ConstructorResolver constructorResolver) {
|
||||
addBeforeDefault(initConstructorResolvers(), constructorResolver);
|
||||
}
|
||||
|
||||
public boolean removeConstructorResolver(ConstructorResolver resolver) {
|
||||
return initConstructorResolvers().remove(resolver);
|
||||
/**
|
||||
* Remove the supplied constructor resolver from this evaluation context.
|
||||
* @param constructorResolver the constructor resolver to remove
|
||||
* @return {@code true} if the constructor resolver was removed, {@code false}
|
||||
* if the constructor resolver was not configured in this evaluation context
|
||||
< * @see #getConstructorResolvers()
|
||||
* @see #setConstructorResolvers(List)
|
||||
* @see #addConstructorResolver(ConstructorResolver)
|
||||
*/
|
||||
public boolean removeConstructorResolver(ConstructorResolver constructorResolver) {
|
||||
return initConstructorResolvers().remove(constructorResolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the list of method resolvers to use in this evaluation context.
|
||||
* <p>Replaces any previously configured method resolvers.
|
||||
*/
|
||||
public void setMethodResolvers(List<MethodResolver> methodResolvers) {
|
||||
this.methodResolvers = methodResolvers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of method resolvers to use in this evaluation context.
|
||||
*/
|
||||
@Override
|
||||
public List<MethodResolver> getMethodResolvers() {
|
||||
return initMethodResolvers();
|
||||
}
|
||||
|
||||
public void addMethodResolver(MethodResolver resolver) {
|
||||
addBeforeDefault(initMethodResolvers(), resolver);
|
||||
/**
|
||||
* Add the supplied method resolver to this evaluation context.
|
||||
* @param methodResolver the method resolver to add
|
||||
* @see #getMethodResolvers()
|
||||
* @see #setMethodResolvers(List)
|
||||
* @see #removeMethodResolver(MethodResolver)
|
||||
*/
|
||||
public void addMethodResolver(MethodResolver methodResolver) {
|
||||
addBeforeDefault(initMethodResolvers(), methodResolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the supplied method resolver from this evaluation context.
|
||||
* @param methodResolver the method resolver to remove
|
||||
* @return {@code true} if the method resolver was removed, {@code false}
|
||||
* if the method resolver was not configured in this evaluation context
|
||||
* @see #getMethodResolvers()
|
||||
* @see #setMethodResolvers(List)
|
||||
* @see #addMethodResolver(MethodResolver)
|
||||
*/
|
||||
public boolean removeMethodResolver(MethodResolver methodResolver) {
|
||||
return initMethodResolvers().remove(methodResolver);
|
||||
}
|
||||
|
||||
public void setBeanResolver(BeanResolver beanResolver) {
|
||||
/**
|
||||
* Set the {@link BeanResolver} to use for looking up beans, if any.
|
||||
*/
|
||||
public void setBeanResolver(@Nullable BeanResolver beanResolver) {
|
||||
this.beanResolver = beanResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configured {@link BeanResolver} for looking up beans, if any.
|
||||
*/
|
||||
@Override
|
||||
public @Nullable BeanResolver getBeanResolver() {
|
||||
return this.beanResolver;
|
||||
|
@ -276,11 +366,17 @@ public class StandardEvaluationContext implements EvaluationContext {
|
|||
return this.typeLocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link TypeConverter} for value conversion.
|
||||
*/
|
||||
public void setTypeConverter(TypeConverter typeConverter) {
|
||||
Assert.notNull(typeConverter, "TypeConverter must not be null");
|
||||
this.typeConverter = typeConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configured {@link TypeConverter} for value conversion.
|
||||
*/
|
||||
@Override
|
||||
public TypeConverter getTypeConverter() {
|
||||
if (this.typeConverter == null) {
|
||||
|
@ -289,21 +385,33 @@ public class StandardEvaluationContext implements EvaluationContext {
|
|||
return this.typeConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link TypeComparator} for comparing pairs of objects.
|
||||
*/
|
||||
public void setTypeComparator(TypeComparator typeComparator) {
|
||||
Assert.notNull(typeComparator, "TypeComparator must not be null");
|
||||
this.typeComparator = typeComparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configured {@link TypeComparator} for comparing pairs of objects.
|
||||
*/
|
||||
@Override
|
||||
public TypeComparator getTypeComparator() {
|
||||
return this.typeComparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link OperatorOverloader} for mathematical operations.
|
||||
*/
|
||||
public void setOperatorOverloader(OperatorOverloader operatorOverloader) {
|
||||
Assert.notNull(operatorOverloader, "OperatorOverloader must not be null");
|
||||
this.operatorOverloader = operatorOverloader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configured {@link OperatorOverloader} for mathematical operations.
|
||||
*/
|
||||
@Override
|
||||
public OperatorOverloader getOperatorOverloader() {
|
||||
return this.operatorOverloader;
|
||||
|
|
Loading…
Reference in New Issue