Stop resolving CachingConfigurer instances eagerly
Closes gh-27751
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,9 +16,12 @@
|
||||
|
||||
package org.springframework.cache.annotation;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.interceptor.CacheErrorHandler;
|
||||
@@ -30,6 +33,7 @@ import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.function.SingletonSupplier;
|
||||
|
||||
/**
|
||||
* Abstract base {@code @Configuration} class providing common structure
|
||||
@@ -70,29 +74,60 @@ public abstract class AbstractCachingConfiguration implements ImportAware {
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
void setConfigurers(Collection<CachingConfigurer> configurers) {
|
||||
if (CollectionUtils.isEmpty(configurers)) {
|
||||
return;
|
||||
}
|
||||
if (configurers.size() > 1) {
|
||||
throw new IllegalStateException(configurers.size() + " implementations of " +
|
||||
"CachingConfigurer were found when only 1 was expected. " +
|
||||
"Refactor the configuration such that CachingConfigurer is " +
|
||||
"implemented only once or not at all.");
|
||||
}
|
||||
CachingConfigurer configurer = configurers.iterator().next();
|
||||
useCachingConfigurer(configurer);
|
||||
@Autowired
|
||||
void setConfigurers(ObjectProvider<CachingConfigurer> configurers) {
|
||||
Supplier<CachingConfigurer> cachingConfigurer = () -> {
|
||||
List<CachingConfigurer> candidates = configurers.stream().collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(candidates)) {
|
||||
return null;
|
||||
}
|
||||
if (candidates.size() > 1) {
|
||||
throw new IllegalStateException(candidates.size() + " implementations of " +
|
||||
"CachingConfigurer were found when only 1 was expected. " +
|
||||
"Refactor the configuration such that CachingConfigurer is " +
|
||||
"implemented only once or not at all.");
|
||||
}
|
||||
return candidates.get(0);
|
||||
};
|
||||
useCachingConfigurer(new CachingConfigurerSupplier(cachingConfigurer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the configuration from the nominated {@link CachingConfigurer}.
|
||||
*/
|
||||
protected void useCachingConfigurer(CachingConfigurer config) {
|
||||
this.cacheManager = config::cacheManager;
|
||||
this.cacheResolver = config::cacheResolver;
|
||||
this.keyGenerator = config::keyGenerator;
|
||||
this.errorHandler = config::errorHandler;
|
||||
protected void useCachingConfigurer(CachingConfigurerSupplier cachingConfigurerSupplier) {
|
||||
this.cacheManager = cachingConfigurerSupplier.adapt(CachingConfigurer::cacheManager);
|
||||
this.cacheResolver = cachingConfigurerSupplier.adapt(CachingConfigurer::cacheResolver);
|
||||
this.keyGenerator = cachingConfigurerSupplier.adapt(CachingConfigurer::keyGenerator);
|
||||
this.errorHandler = cachingConfigurerSupplier.adapt(CachingConfigurer::errorHandler);
|
||||
}
|
||||
|
||||
|
||||
protected static class CachingConfigurerSupplier {
|
||||
|
||||
private final Supplier<CachingConfigurer> supplier;
|
||||
|
||||
public CachingConfigurerSupplier(Supplier<CachingConfigurer> supplier) {
|
||||
this.supplier = SingletonSupplier.of(supplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapt the {@link CachingConfigurer} supplier to another supplier
|
||||
* provided by the specified mapping function. If the underlying
|
||||
* {@link CachingConfigurer} is {@code null}, {@code null} is returned
|
||||
* and the mapping function is not invoked.
|
||||
* @param provider the provider to use to adapt the supplier
|
||||
* @param <T> the type of the supplier
|
||||
* @return another supplier mapped by the specified function
|
||||
*/
|
||||
@Nullable
|
||||
public <T> Supplier<T> adapt(Function<CachingConfigurer, T> provider) {
|
||||
return () -> {
|
||||
CachingConfigurer cachingConfigurer = this.supplier.get();
|
||||
return (cachingConfigurer != null) ? provider.apply(cachingConfigurer) : null;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user