Create spring-boot-cache module
This commit is contained in:
committed by
Phillip Webb
parent
dbd5c9847d
commit
63255f3c62
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import org.cache2k.Cache2kBuilder;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the default
|
||||
* setup for caches added to the manager through addCaches and for dynamically created
|
||||
* caches.
|
||||
*
|
||||
* @author Jens Wilke
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public interface Cache2kBuilderCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the default cache settings.
|
||||
* @param builder the builder to customize
|
||||
*/
|
||||
void customize(Cache2kBuilder<?, ?> builder);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.cache2k.Cache2kBuilder;
|
||||
import org.cache2k.extra.spring.SpringCache2kCacheManager;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Cache2k cache configuration.
|
||||
*
|
||||
* @author Jens Wilke
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ Cache2kBuilder.class, SpringCache2kCacheManager.class })
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@Conditional(CacheCondition.class)
|
||||
class Cache2kCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
SpringCache2kCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers customizers,
|
||||
ObjectProvider<Cache2kBuilderCustomizer> cache2kBuilderCustomizers) {
|
||||
SpringCache2kCacheManager cacheManager = new SpringCache2kCacheManager();
|
||||
cacheManager.defaultSetup(configureDefaults(cache2kBuilderCustomizers));
|
||||
Collection<String> cacheNames = cacheProperties.getCacheNames();
|
||||
if (!CollectionUtils.isEmpty(cacheNames)) {
|
||||
cacheManager.setDefaultCacheNames(cacheNames);
|
||||
}
|
||||
return customizers.customize(cacheManager);
|
||||
}
|
||||
|
||||
private Function<Cache2kBuilder<?, ?>, Cache2kBuilder<?, ?>> configureDefaults(
|
||||
ObjectProvider<Cache2kBuilderCustomizer> cache2kBuilderCustomizers) {
|
||||
return (builder) -> {
|
||||
cache2kBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
return builder;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.cache.CacheType;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.cache.autoconfigure.CacheAutoConfiguration.CacheConfigurationImportSelector;
|
||||
import org.springframework.boot.cache.autoconfigure.CacheAutoConfiguration.CacheManagerEntityManagerFactoryDependsOnConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.jpa.autoconfigure.EntityManagerFactoryDependsOnPostProcessor;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.interceptor.CacheAspectSupport;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.ImportSelector;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for the cache abstraction. Creates a
|
||||
* {@link CacheManager} if necessary when caching is enabled via
|
||||
* {@link EnableCaching @EnableCaching}.
|
||||
* <p>
|
||||
* Cache store can be auto-detected or specified explicitly through configuration.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.0.0
|
||||
* @see EnableCaching
|
||||
*/
|
||||
@AutoConfiguration(afterName = { "org.springframework.boot.data.couchbase.autoconfigure.CouchbaseDataAutoConfiguration",
|
||||
"org.springframework.boot.data.redis.autoconfigure.RedisAutoConfiguration",
|
||||
"org.springframework.boot.hazelcast.autoconfigure.HazelcastAutoConfiguration",
|
||||
"org.springframework.boot.jpa.autoconfigure.hibernate.HibernateJpaAutoConfiguration" })
|
||||
@ConditionalOnClass(CacheManager.class)
|
||||
@ConditionalOnBean(CacheAspectSupport.class)
|
||||
@ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
|
||||
@EnableConfigurationProperties(CacheProperties.class)
|
||||
@Import({ CacheConfigurationImportSelector.class, CacheManagerEntityManagerFactoryDependsOnConfiguration.class })
|
||||
public class CacheAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public CacheManagerCustomizers cacheManagerCustomizers(ObjectProvider<CacheManagerCustomizer<?>> customizers) {
|
||||
return new CacheManagerCustomizers(customizers.orderedStream().toList());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CacheManagerValidator cacheAutoConfigurationValidator(CacheProperties cacheProperties,
|
||||
ObjectProvider<CacheManager> cacheManager) {
|
||||
return new CacheManagerValidator(cacheProperties, cacheManager);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ EntityManagerFactoryDependsOnPostProcessor.class,
|
||||
LocalContainerEntityManagerFactoryBean.class })
|
||||
@ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
|
||||
@Import(CacheManagerEntityManagerFactoryDependsOnPostProcessor.class)
|
||||
static class CacheManagerEntityManagerFactoryDependsOnConfiguration {
|
||||
|
||||
}
|
||||
|
||||
static class CacheManagerEntityManagerFactoryDependsOnPostProcessor
|
||||
extends EntityManagerFactoryDependsOnPostProcessor {
|
||||
|
||||
CacheManagerEntityManagerFactoryDependsOnPostProcessor() {
|
||||
super("cacheManager");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean used to validate that a CacheManager exists and provide a more meaningful
|
||||
* exception.
|
||||
*/
|
||||
static class CacheManagerValidator implements InitializingBean {
|
||||
|
||||
private final CacheProperties cacheProperties;
|
||||
|
||||
private final ObjectProvider<CacheManager> cacheManager;
|
||||
|
||||
CacheManagerValidator(CacheProperties cacheProperties, ObjectProvider<CacheManager> cacheManager) {
|
||||
this.cacheProperties = cacheProperties;
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
Assert.state(this.cacheManager.getIfAvailable() != null,
|
||||
() -> "No cache manager could be auto-configured, check your configuration (caching type is '"
|
||||
+ this.cacheProperties.getType() + "')");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ImportSelector} to add {@link CacheType} configuration classes.
|
||||
*/
|
||||
static class CacheConfigurationImportSelector implements ImportSelector {
|
||||
|
||||
@Override
|
||||
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
|
||||
CacheType[] types = CacheType.values();
|
||||
String[] imports = new String[types.length];
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
|
||||
}
|
||||
return imports;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import org.springframework.boot.autoconfigure.cache.CacheType;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.boot.context.properties.bind.BindException;
|
||||
import org.springframework.boot.context.properties.bind.BindResult;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.ClassMetadata;
|
||||
|
||||
/**
|
||||
* General cache condition used with all cache configuration classes.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class CacheCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
String sourceClass = "";
|
||||
if (metadata instanceof ClassMetadata classMetadata) {
|
||||
sourceClass = classMetadata.getClassName();
|
||||
}
|
||||
ConditionMessage.Builder message = ConditionMessage.forCondition("Cache", sourceClass);
|
||||
Environment environment = context.getEnvironment();
|
||||
try {
|
||||
BindResult<CacheType> specified = Binder.get(environment).bind("spring.cache.type", CacheType.class);
|
||||
if (!specified.isBound()) {
|
||||
return ConditionOutcome.match(message.because("automatic cache type"));
|
||||
}
|
||||
CacheType required = CacheConfigurations.getType(((AnnotationMetadata) metadata).getClassName());
|
||||
if (specified.get() == required) {
|
||||
return ConditionOutcome.match(message.because(specified.get() + " cache type"));
|
||||
}
|
||||
}
|
||||
catch (BindException ex) {
|
||||
// Ignore
|
||||
}
|
||||
return ConditionOutcome.noMatch(message.because("unknown cache type"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.autoconfigure.cache.CacheType;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Mappings between {@link CacheType} and {@code @Configuration}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Eddú Meléndez
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
final class CacheConfigurations {
|
||||
|
||||
private static final Map<CacheType, String> MAPPINGS;
|
||||
|
||||
static {
|
||||
Map<CacheType, String> mappings = new EnumMap<>(CacheType.class);
|
||||
mappings.put(CacheType.GENERIC, GenericCacheConfiguration.class.getName());
|
||||
mappings.put(CacheType.HAZELCAST, HazelcastCacheConfiguration.class.getName());
|
||||
mappings.put(CacheType.INFINISPAN, InfinispanCacheConfiguration.class.getName());
|
||||
mappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class.getName());
|
||||
mappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class.getName());
|
||||
mappings.put(CacheType.REDIS, RedisCacheConfiguration.class.getName());
|
||||
mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class.getName());
|
||||
mappings.put(CacheType.CACHE2K, Cache2kCacheConfiguration.class.getName());
|
||||
mappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class.getName());
|
||||
mappings.put(CacheType.NONE, NoOpCacheConfiguration.class.getName());
|
||||
MAPPINGS = Collections.unmodifiableMap(mappings);
|
||||
}
|
||||
|
||||
private CacheConfigurations() {
|
||||
}
|
||||
|
||||
static String getConfigurationClass(CacheType cacheType) {
|
||||
String configurationClassName = MAPPINGS.get(cacheType);
|
||||
Assert.state(configurationClassName != null, () -> "Unknown cache type " + cacheType);
|
||||
return configurationClassName;
|
||||
}
|
||||
|
||||
static CacheType getType(String configurationClassName) {
|
||||
for (Map.Entry<CacheType, String> entry : MAPPINGS.entrySet()) {
|
||||
if (entry.getValue().equals(configurationClassName)) {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Unknown configuration class " + configurationClassName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import org.springframework.cache.CacheManager;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the cache
|
||||
* manager before it is fully initialized, in particular to tune its configuration.
|
||||
*
|
||||
* @param <T> the type of the {@link CacheManager}
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface CacheManagerCustomizer<T extends CacheManager> {
|
||||
|
||||
/**
|
||||
* Customize the cache manager.
|
||||
* @param cacheManager the {@code CacheManager} to customize
|
||||
*/
|
||||
void customize(T cacheManager);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.util.LambdaSafe;
|
||||
import org.springframework.cache.CacheManager;
|
||||
|
||||
/**
|
||||
* Invokes the available {@link CacheManagerCustomizer} instances in the context for a
|
||||
* given {@link CacheManager}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public class CacheManagerCustomizers {
|
||||
|
||||
private final List<CacheManagerCustomizer<?>> customizers;
|
||||
|
||||
public CacheManagerCustomizers(List<? extends CacheManagerCustomizer<?>> customizers) {
|
||||
this.customizers = (customizers != null) ? new ArrayList<>(customizers) : Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize the specified {@link CacheManager}. Locates all
|
||||
* {@link CacheManagerCustomizer} beans able to handle the specified instance and
|
||||
* invoke {@link CacheManagerCustomizer#customize(CacheManager)} on them.
|
||||
* @param <T> the type of cache manager
|
||||
* @param cacheManager the cache manager to customize
|
||||
* @return the cache manager
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends CacheManager> T customize(T cacheManager) {
|
||||
LambdaSafe.callbacks(CacheManagerCustomizer.class, this.customizers, cacheManager)
|
||||
.withLogger(CacheManagerCustomizers.class)
|
||||
.invoke((customizer) -> customizer.customize(cacheManager));
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.autoconfigure.cache.CacheType;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Configuration properties for the cache abstraction.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Eddú Meléndez
|
||||
* @author Ryon Day
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@ConfigurationProperties("spring.cache")
|
||||
public class CacheProperties {
|
||||
|
||||
/**
|
||||
* Cache type. By default, auto-detected according to the environment.
|
||||
*/
|
||||
private CacheType type;
|
||||
|
||||
/**
|
||||
* List of cache names to create if supported by the underlying cache manager.
|
||||
* Usually, this disables the ability to create additional caches on-the-fly.
|
||||
*/
|
||||
private List<String> cacheNames = new ArrayList<>();
|
||||
|
||||
private final Caffeine caffeine = new Caffeine();
|
||||
|
||||
private final Couchbase couchbase = new Couchbase();
|
||||
|
||||
private final Infinispan infinispan = new Infinispan();
|
||||
|
||||
private final JCache jcache = new JCache();
|
||||
|
||||
private final Redis redis = new Redis();
|
||||
|
||||
public CacheType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public void setType(CacheType mode) {
|
||||
this.type = mode;
|
||||
}
|
||||
|
||||
public List<String> getCacheNames() {
|
||||
return this.cacheNames;
|
||||
}
|
||||
|
||||
public void setCacheNames(List<String> cacheNames) {
|
||||
this.cacheNames = cacheNames;
|
||||
}
|
||||
|
||||
public Caffeine getCaffeine() {
|
||||
return this.caffeine;
|
||||
}
|
||||
|
||||
public Couchbase getCouchbase() {
|
||||
return this.couchbase;
|
||||
}
|
||||
|
||||
public Infinispan getInfinispan() {
|
||||
return this.infinispan;
|
||||
}
|
||||
|
||||
public JCache getJcache() {
|
||||
return this.jcache;
|
||||
}
|
||||
|
||||
public Redis getRedis() {
|
||||
return this.redis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the config location if set.
|
||||
* @param config the config resource
|
||||
* @return the location or {@code null} if it is not set
|
||||
* @throws IllegalArgumentException if the config attribute is set to an unknown
|
||||
* location
|
||||
*/
|
||||
public Resource resolveConfigLocation(Resource config) {
|
||||
if (config != null) {
|
||||
Assert.isTrue(config.exists(),
|
||||
() -> "'config' resource [%s] must exist".formatted(config.getDescription()));
|
||||
return config;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Caffeine specific cache properties.
|
||||
*/
|
||||
public static class Caffeine {
|
||||
|
||||
/**
|
||||
* The spec to use to create caches. See CaffeineSpec for more details on the spec
|
||||
* format.
|
||||
*/
|
||||
private String spec;
|
||||
|
||||
public String getSpec() {
|
||||
return this.spec;
|
||||
}
|
||||
|
||||
public void setSpec(String spec) {
|
||||
this.spec = spec;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Couchbase specific cache properties.
|
||||
*/
|
||||
public static class Couchbase {
|
||||
|
||||
/**
|
||||
* Entry expiration. By default the entries never expire. Note that this value is
|
||||
* ultimately converted to seconds.
|
||||
*/
|
||||
private Duration expiration;
|
||||
|
||||
public Duration getExpiration() {
|
||||
return this.expiration;
|
||||
}
|
||||
|
||||
public void setExpiration(Duration expiration) {
|
||||
this.expiration = expiration;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Infinispan specific cache properties.
|
||||
*/
|
||||
public static class Infinispan {
|
||||
|
||||
/**
|
||||
* The location of the configuration file to use to initialize Infinispan.
|
||||
*/
|
||||
private Resource config;
|
||||
|
||||
public Resource getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
public void setConfig(Resource config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* JCache (JSR-107) specific cache properties.
|
||||
*/
|
||||
public static class JCache {
|
||||
|
||||
/**
|
||||
* The location of the configuration file to use to initialize the cache manager.
|
||||
* The configuration file is dependent of the underlying cache implementation.
|
||||
*/
|
||||
private Resource config;
|
||||
|
||||
/**
|
||||
* Fully qualified name of the CachingProvider implementation to use to retrieve
|
||||
* the JSR-107 compliant cache manager. Needed only if more than one JSR-107
|
||||
* implementation is available on the classpath.
|
||||
*/
|
||||
private String provider;
|
||||
|
||||
public String getProvider() {
|
||||
return this.provider;
|
||||
}
|
||||
|
||||
public void setProvider(String provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
public Resource getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
public void setConfig(Resource config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Redis-specific cache properties.
|
||||
*/
|
||||
public static class Redis {
|
||||
|
||||
/**
|
||||
* Entry expiration. By default the entries never expire.
|
||||
*/
|
||||
private Duration timeToLive;
|
||||
|
||||
/**
|
||||
* Allow caching null values.
|
||||
*/
|
||||
private boolean cacheNullValues = true;
|
||||
|
||||
/**
|
||||
* Key prefix.
|
||||
*/
|
||||
private String keyPrefix;
|
||||
|
||||
/**
|
||||
* Whether to use the key prefix when writing to Redis.
|
||||
*/
|
||||
private boolean useKeyPrefix = true;
|
||||
|
||||
/**
|
||||
* Whether to enable cache statistics.
|
||||
*/
|
||||
private boolean enableStatistics;
|
||||
|
||||
public Duration getTimeToLive() {
|
||||
return this.timeToLive;
|
||||
}
|
||||
|
||||
public void setTimeToLive(Duration timeToLive) {
|
||||
this.timeToLive = timeToLive;
|
||||
}
|
||||
|
||||
public boolean isCacheNullValues() {
|
||||
return this.cacheNullValues;
|
||||
}
|
||||
|
||||
public void setCacheNullValues(boolean cacheNullValues) {
|
||||
this.cacheNullValues = cacheNullValues;
|
||||
}
|
||||
|
||||
public String getKeyPrefix() {
|
||||
return this.keyPrefix;
|
||||
}
|
||||
|
||||
public void setKeyPrefix(String keyPrefix) {
|
||||
this.keyPrefix = keyPrefix;
|
||||
}
|
||||
|
||||
public boolean isUseKeyPrefix() {
|
||||
return this.useKeyPrefix;
|
||||
}
|
||||
|
||||
public void setUseKeyPrefix(boolean useKeyPrefix) {
|
||||
this.useKeyPrefix = useKeyPrefix;
|
||||
}
|
||||
|
||||
public boolean isEnableStatistics() {
|
||||
return this.enableStatistics;
|
||||
}
|
||||
|
||||
public void setEnableStatistics(boolean enableStatistics) {
|
||||
this.enableStatistics = enableStatistics;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.CacheLoader;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.CaffeineSpec;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.caffeine.CaffeineCacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Caffeine cache configuration.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ Caffeine.class, CaffeineCacheManager.class })
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@Conditional({ CacheCondition.class })
|
||||
class CaffeineCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
CaffeineCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers customizers,
|
||||
ObjectProvider<Caffeine<Object, Object>> caffeine, ObjectProvider<CaffeineSpec> caffeineSpec,
|
||||
ObjectProvider<CacheLoader<Object, Object>> cacheLoader) {
|
||||
CaffeineCacheManager cacheManager = createCacheManager(cacheProperties, caffeine, caffeineSpec, cacheLoader);
|
||||
List<String> cacheNames = cacheProperties.getCacheNames();
|
||||
if (!CollectionUtils.isEmpty(cacheNames)) {
|
||||
cacheManager.setCacheNames(cacheNames);
|
||||
}
|
||||
return customizers.customize(cacheManager);
|
||||
}
|
||||
|
||||
private CaffeineCacheManager createCacheManager(CacheProperties cacheProperties,
|
||||
ObjectProvider<Caffeine<Object, Object>> caffeine, ObjectProvider<CaffeineSpec> caffeineSpec,
|
||||
ObjectProvider<CacheLoader<Object, Object>> cacheLoader) {
|
||||
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
|
||||
setCacheBuilder(cacheProperties, caffeineSpec.getIfAvailable(), caffeine.getIfAvailable(), cacheManager);
|
||||
cacheLoader.ifAvailable(cacheManager::setCacheLoader);
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
private void setCacheBuilder(CacheProperties cacheProperties, CaffeineSpec caffeineSpec,
|
||||
Caffeine<Object, Object> caffeine, CaffeineCacheManager cacheManager) {
|
||||
String specification = cacheProperties.getCaffeine().getSpec();
|
||||
if (StringUtils.hasText(specification)) {
|
||||
cacheManager.setCacheSpecification(specification);
|
||||
}
|
||||
else if (caffeineSpec != null) {
|
||||
cacheManager.setCaffeineSpec(caffeineSpec);
|
||||
}
|
||||
else if (caffeine != null) {
|
||||
cacheManager.setCaffeine(caffeine);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.java.Cluster;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.cache.autoconfigure.CacheProperties.Couchbase;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.couchbase.CouchbaseClientFactory;
|
||||
import org.springframework.data.couchbase.cache.CouchbaseCacheManager;
|
||||
import org.springframework.data.couchbase.cache.CouchbaseCacheManager.CouchbaseCacheManagerBuilder;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Couchbase cache configuration.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ Cluster.class, CouchbaseClientFactory.class, CouchbaseCacheManager.class })
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@ConditionalOnSingleCandidate(CouchbaseClientFactory.class)
|
||||
@Conditional(CacheCondition.class)
|
||||
class CouchbaseCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
CouchbaseCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers customizers,
|
||||
ObjectProvider<CouchbaseCacheManagerBuilderCustomizer> couchbaseCacheManagerBuilderCustomizers,
|
||||
CouchbaseClientFactory clientFactory) {
|
||||
List<String> cacheNames = cacheProperties.getCacheNames();
|
||||
CouchbaseCacheManagerBuilder builder = CouchbaseCacheManager.builder(clientFactory);
|
||||
Couchbase couchbase = cacheProperties.getCouchbase();
|
||||
org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration config = org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration
|
||||
.defaultCacheConfig();
|
||||
if (couchbase.getExpiration() != null) {
|
||||
config = config.entryExpiry(couchbase.getExpiration());
|
||||
}
|
||||
builder.cacheDefaults(config);
|
||||
if (!ObjectUtils.isEmpty(cacheNames)) {
|
||||
builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
|
||||
}
|
||||
couchbaseCacheManagerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
CouchbaseCacheManager cacheManager = builder.build();
|
||||
return customizers.customize(cacheManager);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import org.springframework.data.couchbase.cache.CouchbaseCacheManager;
|
||||
import org.springframework.data.couchbase.cache.CouchbaseCacheManager.CouchbaseCacheManagerBuilder;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the
|
||||
* {@link CouchbaseCacheManagerBuilder} before it is used to build the auto-configured
|
||||
* {@link CouchbaseCacheManager}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface CouchbaseCacheManagerBuilderCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the {@link CouchbaseCacheManagerBuilder}.
|
||||
* @param builder the builder to customize
|
||||
*/
|
||||
void customize(CouchbaseCacheManagerBuilder builder);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.support.SimpleCacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Generic cache configuration based on arbitrary {@link Cache} instances defined in the
|
||||
* context.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnBean(Cache.class)
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@Conditional(CacheCondition.class)
|
||||
class GenericCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
SimpleCacheManager cacheManager(CacheManagerCustomizers customizers, Collection<Cache> caches) {
|
||||
SimpleCacheManager cacheManager = new SimpleCacheManager();
|
||||
cacheManager.setCaches(caches);
|
||||
return customizers.customize(cacheManager);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.spring.cache.HazelcastCacheManager;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.hazelcast.autoconfigure.HazelcastAutoConfiguration;
|
||||
import org.springframework.boot.hazelcast.autoconfigure.HazelcastConfigResourceCondition;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Hazelcast cache configuration. Can either reuse the {@link HazelcastInstance} that has
|
||||
* been configured by the general {@link HazelcastAutoConfiguration} or create a separate
|
||||
* one if the {@code spring.cache.hazelcast.config} property has been set.
|
||||
* <p>
|
||||
* If the {@link HazelcastAutoConfiguration} has been disabled, an attempt to configure a
|
||||
* default {@link HazelcastInstance} is still made, using the same defaults.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @see HazelcastConfigResourceCondition
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ HazelcastInstance.class, HazelcastCacheManager.class })
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@Conditional(CacheCondition.class)
|
||||
@ConditionalOnSingleCandidate(HazelcastInstance.class)
|
||||
class HazelcastCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
HazelcastCacheManager cacheManager(CacheManagerCustomizers customizers,
|
||||
HazelcastInstance existingHazelcastInstance) {
|
||||
HazelcastCacheManager cacheManager = new HazelcastCacheManager(existingHazelcastInstance);
|
||||
return customizers.customize(cacheManager);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* JCache customization for Hazelcast.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(HazelcastInstance.class)
|
||||
class HazelcastJCacheCustomizationConfiguration {
|
||||
|
||||
@Bean
|
||||
HazelcastPropertiesCustomizer hazelcastPropertiesCustomizer(ObjectProvider<HazelcastInstance> hazelcastInstance,
|
||||
CacheProperties cacheProperties) {
|
||||
return new HazelcastPropertiesCustomizer(hazelcastInstance.getIfUnique(), cacheProperties);
|
||||
}
|
||||
|
||||
static class HazelcastPropertiesCustomizer implements JCachePropertiesCustomizer {
|
||||
|
||||
private final HazelcastInstance hazelcastInstance;
|
||||
|
||||
private final CacheProperties cacheProperties;
|
||||
|
||||
HazelcastPropertiesCustomizer(HazelcastInstance hazelcastInstance, CacheProperties cacheProperties) {
|
||||
this.hazelcastInstance = hazelcastInstance;
|
||||
this.cacheProperties = cacheProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(Properties properties) {
|
||||
Resource configLocation = this.cacheProperties
|
||||
.resolveConfigLocation(this.cacheProperties.getJcache().getConfig());
|
||||
if (configLocation != null) {
|
||||
// Hazelcast does not use the URI as a mean to specify a custom config.
|
||||
properties.setProperty("hazelcast.config.location", toUri(configLocation).toString());
|
||||
}
|
||||
else if (this.hazelcastInstance != null) {
|
||||
properties.put("hazelcast.instance.itself", this.hazelcastInstance);
|
||||
}
|
||||
}
|
||||
|
||||
private static URI toUri(Resource config) {
|
||||
try {
|
||||
return config.getURI();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalArgumentException("Could not get URI from " + config, ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.infinispan.configuration.cache.ConfigurationBuilder;
|
||||
import org.infinispan.manager.DefaultCacheManager;
|
||||
import org.infinispan.manager.EmbeddedCacheManager;
|
||||
import org.infinispan.spring.embedded.provider.SpringEmbeddedCacheManager;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Infinispan cache configuration.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
* @author Stephane Nicoll
|
||||
* @author Raja Kolli
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(SpringEmbeddedCacheManager.class)
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@Conditional(CacheCondition.class)
|
||||
public class InfinispanCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
public SpringEmbeddedCacheManager cacheManager(CacheManagerCustomizers customizers,
|
||||
EmbeddedCacheManager embeddedCacheManager) {
|
||||
SpringEmbeddedCacheManager cacheManager = new SpringEmbeddedCacheManager(embeddedCacheManager);
|
||||
return customizers.customize(cacheManager);
|
||||
}
|
||||
|
||||
@Bean(destroyMethod = "stop")
|
||||
@ConditionalOnMissingBean
|
||||
public EmbeddedCacheManager infinispanCacheManager(CacheProperties cacheProperties,
|
||||
ObjectProvider<ConfigurationBuilder> defaultConfigurationBuilder) throws IOException {
|
||||
EmbeddedCacheManager cacheManager = createEmbeddedCacheManager(cacheProperties);
|
||||
List<String> cacheNames = cacheProperties.getCacheNames();
|
||||
if (!CollectionUtils.isEmpty(cacheNames)) {
|
||||
cacheNames.forEach((cacheName) -> cacheManager.defineConfiguration(cacheName,
|
||||
getDefaultCacheConfiguration(defaultConfigurationBuilder.getIfAvailable())));
|
||||
}
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
private EmbeddedCacheManager createEmbeddedCacheManager(CacheProperties cacheProperties) throws IOException {
|
||||
Resource location = cacheProperties.resolveConfigLocation(cacheProperties.getInfinispan().getConfig());
|
||||
if (location != null) {
|
||||
try (InputStream in = location.getInputStream()) {
|
||||
return new DefaultCacheManager(in);
|
||||
}
|
||||
}
|
||||
return new DefaultCacheManager();
|
||||
}
|
||||
|
||||
private org.infinispan.configuration.cache.Configuration getDefaultCacheConfiguration(
|
||||
ConfigurationBuilder defaultConfigurationBuilder) {
|
||||
if (defaultConfigurationBuilder != null) {
|
||||
return defaultConfigurationBuilder.build();
|
||||
}
|
||||
return new ConfigurationBuilder().build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.cache.CacheManager;
|
||||
import javax.cache.Caching;
|
||||
import javax.cache.configuration.MutableConfiguration;
|
||||
import javax.cache.spi.CachingProvider;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.cache.jcache.JCacheCacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Cache configuration for JSR-107 compliant providers.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ Caching.class, JCacheCacheManager.class })
|
||||
@ConditionalOnMissingBean(org.springframework.cache.CacheManager.class)
|
||||
@Conditional({ CacheCondition.class, JCacheCacheConfiguration.JCacheAvailableCondition.class })
|
||||
@Import(HazelcastJCacheCustomizationConfiguration.class)
|
||||
class JCacheCacheConfiguration implements BeanClassLoaderAware {
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
@Bean
|
||||
JCacheCacheManager cacheManager(CacheManagerCustomizers customizers, CacheManager jCacheCacheManager) {
|
||||
JCacheCacheManager cacheManager = new JCacheCacheManager(jCacheCacheManager);
|
||||
return customizers.customize(cacheManager);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
CacheManager jCacheCacheManager(CacheProperties cacheProperties,
|
||||
ObjectProvider<javax.cache.configuration.Configuration<?, ?>> defaultCacheConfiguration,
|
||||
ObjectProvider<JCacheManagerCustomizer> cacheManagerCustomizers,
|
||||
ObjectProvider<JCachePropertiesCustomizer> cachePropertiesCustomizers) throws IOException {
|
||||
CacheManager jCacheCacheManager = createCacheManager(cacheProperties, cachePropertiesCustomizers);
|
||||
List<String> cacheNames = cacheProperties.getCacheNames();
|
||||
if (!CollectionUtils.isEmpty(cacheNames)) {
|
||||
for (String cacheName : cacheNames) {
|
||||
jCacheCacheManager.createCache(cacheName,
|
||||
defaultCacheConfiguration.getIfAvailable(MutableConfiguration::new));
|
||||
}
|
||||
}
|
||||
cacheManagerCustomizers.orderedStream().forEach((customizer) -> customizer.customize(jCacheCacheManager));
|
||||
return jCacheCacheManager;
|
||||
}
|
||||
|
||||
private CacheManager createCacheManager(CacheProperties cacheProperties,
|
||||
ObjectProvider<JCachePropertiesCustomizer> cachePropertiesCustomizers) throws IOException {
|
||||
CachingProvider cachingProvider = getCachingProvider(cacheProperties.getJcache().getProvider());
|
||||
Properties properties = createCacheManagerProperties(cachePropertiesCustomizers);
|
||||
Resource configLocation = cacheProperties.resolveConfigLocation(cacheProperties.getJcache().getConfig());
|
||||
if (configLocation != null) {
|
||||
return cachingProvider.getCacheManager(configLocation.getURI(), this.beanClassLoader, properties);
|
||||
}
|
||||
return cachingProvider.getCacheManager(null, this.beanClassLoader, properties);
|
||||
}
|
||||
|
||||
private CachingProvider getCachingProvider(String cachingProviderFqn) {
|
||||
if (StringUtils.hasText(cachingProviderFqn)) {
|
||||
return Caching.getCachingProvider(cachingProviderFqn);
|
||||
}
|
||||
return Caching.getCachingProvider();
|
||||
}
|
||||
|
||||
private Properties createCacheManagerProperties(
|
||||
ObjectProvider<JCachePropertiesCustomizer> cachePropertiesCustomizers) {
|
||||
Properties properties = new Properties();
|
||||
cachePropertiesCustomizers.orderedStream().forEach((customizer) -> customizer.customize(properties));
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if JCache is available. This either kicks in if a provider is available
|
||||
* as defined per {@link JCacheProviderAvailableCondition} or if a
|
||||
* {@link CacheManager} has already been defined.
|
||||
*/
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
static class JCacheAvailableCondition extends AnyNestedCondition {
|
||||
|
||||
JCacheAvailableCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@Conditional(JCacheProviderAvailableCondition.class)
|
||||
static class JCacheProvider {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnSingleCandidate(CacheManager.class)
|
||||
static class CustomJCacheCacheManager {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a JCache provider is available. This either kicks in if a default
|
||||
* {@link CachingProvider} has been found or if the property referring to the provider
|
||||
* to use has been set.
|
||||
*/
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
static class JCacheProviderAvailableCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage.forCondition("JCache");
|
||||
String providerProperty = "spring.cache.jcache.provider";
|
||||
if (context.getEnvironment().containsProperty(providerProperty)) {
|
||||
return ConditionOutcome.match(message.because("JCache provider specified"));
|
||||
}
|
||||
Iterator<CachingProvider> providers = Caching.getCachingProviders().iterator();
|
||||
if (!providers.hasNext()) {
|
||||
return ConditionOutcome.noMatch(message.didNotFind("JSR-107 provider").atAll());
|
||||
}
|
||||
providers.next();
|
||||
if (providers.hasNext()) {
|
||||
return ConditionOutcome.noMatch(message.foundExactly("multiple JSR-107 providers"));
|
||||
}
|
||||
return ConditionOutcome.match(message.foundExactly("single JSR-107 provider"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import javax.cache.CacheManager;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the cache
|
||||
* manager before it is used, in particular to create additional caches.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface JCacheManagerCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the cache manager.
|
||||
* @param cacheManager the {@code javax.cache.CacheManager} to customize
|
||||
*/
|
||||
void customize(CacheManager cacheManager);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.cache.CacheManager;
|
||||
import javax.cache.spi.CachingProvider;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the properties
|
||||
* used by the {@link CachingProvider} to create the {@link CacheManager}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.0.0
|
||||
* @see CachingProvider#getCacheManager(java.net.URI, ClassLoader, Properties)
|
||||
*/
|
||||
public interface JCachePropertiesCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the properties.
|
||||
* @param properties the current properties
|
||||
*/
|
||||
void customize(Properties properties);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.support.NoOpCacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* No-op cache configuration used to disable caching through configuration.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@Conditional(CacheCondition.class)
|
||||
class NoOpCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
NoOpCacheManager cacheManager() {
|
||||
return new NoOpCacheManager();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.cache.autoconfigure.CacheProperties.Redis;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||
import org.springframework.data.redis.cache.RedisCacheManager.RedisCacheManagerBuilder;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair;
|
||||
|
||||
/**
|
||||
* Redis cache configuration.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Mark Paluch
|
||||
* @author Ryon Day
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(RedisConnectionFactory.class)
|
||||
@AutoConfigureAfter(name = "org.springframework.boot.data.redis.autoconfigure.RedisAutoConfiguration")
|
||||
@ConditionalOnBean(RedisConnectionFactory.class)
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@Conditional(CacheCondition.class)
|
||||
class RedisCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
RedisCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers cacheManagerCustomizers,
|
||||
ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration,
|
||||
ObjectProvider<RedisCacheManagerBuilderCustomizer> redisCacheManagerBuilderCustomizers,
|
||||
RedisConnectionFactory redisConnectionFactory, ResourceLoader resourceLoader) {
|
||||
RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory)
|
||||
.cacheDefaults(
|
||||
determineConfiguration(cacheProperties, redisCacheConfiguration, resourceLoader.getClassLoader()));
|
||||
List<String> cacheNames = cacheProperties.getCacheNames();
|
||||
if (!cacheNames.isEmpty()) {
|
||||
builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
|
||||
}
|
||||
if (cacheProperties.getRedis().isEnableStatistics()) {
|
||||
builder.enableStatistics();
|
||||
}
|
||||
redisCacheManagerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
return cacheManagerCustomizers.customize(builder.build());
|
||||
}
|
||||
|
||||
private org.springframework.data.redis.cache.RedisCacheConfiguration determineConfiguration(
|
||||
CacheProperties cacheProperties,
|
||||
ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration,
|
||||
ClassLoader classLoader) {
|
||||
return redisCacheConfiguration.getIfAvailable(() -> createConfiguration(cacheProperties, classLoader));
|
||||
}
|
||||
|
||||
private org.springframework.data.redis.cache.RedisCacheConfiguration createConfiguration(
|
||||
CacheProperties cacheProperties, ClassLoader classLoader) {
|
||||
Redis redisProperties = cacheProperties.getRedis();
|
||||
org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration
|
||||
.defaultCacheConfig();
|
||||
config = config
|
||||
.serializeValuesWith(SerializationPair.fromSerializer(new JdkSerializationRedisSerializer(classLoader)));
|
||||
if (redisProperties.getTimeToLive() != null) {
|
||||
config = config.entryTtl(redisProperties.getTimeToLive());
|
||||
}
|
||||
if (redisProperties.getKeyPrefix() != null) {
|
||||
config = config.prefixCacheNameWith(redisProperties.getKeyPrefix());
|
||||
}
|
||||
if (!redisProperties.isCacheNullValues()) {
|
||||
config = config.disableCachingNullValues();
|
||||
}
|
||||
if (!redisProperties.isUseKeyPrefix()) {
|
||||
config = config.disableKeyPrefix();
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import org.springframework.data.redis.cache.RedisCacheManager.RedisCacheManagerBuilder;
|
||||
|
||||
/**
|
||||
* Callback interface that can be used to customize a {@link RedisCacheManagerBuilder}.
|
||||
*
|
||||
* @author Dmytro Nosan
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface RedisCacheManagerBuilderCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the {@link RedisCacheManagerBuilder}.
|
||||
* @param builder the builder to customize
|
||||
*/
|
||||
void customize(RedisCacheManagerBuilder builder);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Simplest cache configuration, usually used as a fallback.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@Conditional(CacheCondition.class)
|
||||
class SimpleCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
ConcurrentMapCacheManager cacheManager(CacheProperties cacheProperties,
|
||||
CacheManagerCustomizers cacheManagerCustomizers) {
|
||||
ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
|
||||
List<String> cacheNames = cacheProperties.getCacheNames();
|
||||
if (!cacheNames.isEmpty()) {
|
||||
cacheManager.setCacheNames(cacheNames);
|
||||
}
|
||||
return cacheManagerCustomizers.customize(cacheManager);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for the cache abstraction.
|
||||
*/
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"groups": [],
|
||||
"properties": [],
|
||||
"hints": [
|
||||
{
|
||||
"name": "spring.cache.jcache.provider",
|
||||
"providers": [
|
||||
{
|
||||
"name": "class-reference",
|
||||
"parameters": {
|
||||
"target": "javax.cache.spi.CachingProvider"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.springframework.boot.cache.autoconfigure.CacheAutoConfiguration
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.hazelcast.spring.cache.HazelcastCacheManager;
|
||||
import org.cache2k.extra.spring.SpringCache2kCacheManager;
|
||||
import org.infinispan.spring.embedded.provider.SpringEmbeddedCacheManager;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.ContextConsumer;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.caffeine.CaffeineCacheManager;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
|
||||
import org.springframework.cache.support.SimpleCacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.couchbase.cache.CouchbaseCacheManager;
|
||||
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Base class for {@link CacheAutoConfiguration} tests.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
abstract class AbstractCacheAutoConfigurationTests {
|
||||
|
||||
protected final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(CacheAutoConfiguration.class));
|
||||
|
||||
protected <T extends CacheManager> T getCacheManager(AssertableApplicationContext loaded, Class<T> type) {
|
||||
CacheManager cacheManager = loaded.getBean(CacheManager.class);
|
||||
assertThat(cacheManager).as("Wrong cache manager type").isInstanceOf(type);
|
||||
return type.cast(cacheManager);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected ContextConsumer<AssertableApplicationContext> verifyCustomizers(String... expectedCustomizerNames) {
|
||||
return (context) -> {
|
||||
CacheManager cacheManager = getCacheManager(context, CacheManager.class);
|
||||
List<String> expected = new ArrayList<>(Arrays.asList(expectedCustomizerNames));
|
||||
Map<String, CacheManagerTestCustomizer> customizer = context
|
||||
.getBeansOfType(CacheManagerTestCustomizer.class);
|
||||
customizer.forEach((key, value) -> {
|
||||
if (expected.contains(key)) {
|
||||
expected.remove(key);
|
||||
assertThat(value.cacheManager).isSameAs(cacheManager);
|
||||
}
|
||||
else {
|
||||
assertThat(value.cacheManager).isNull();
|
||||
}
|
||||
});
|
||||
assertThat(expected).isEmpty();
|
||||
};
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CacheManagerCustomizersConfiguration {
|
||||
|
||||
@Bean
|
||||
CacheManagerCustomizer<CacheManager> allCacheManagerCustomizer() {
|
||||
return new CacheManagerTestCustomizer<>() {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
CacheManagerCustomizer<ConcurrentMapCacheManager> simpleCacheManagerCustomizer() {
|
||||
return new CacheManagerTestCustomizer<>() {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
CacheManagerCustomizer<SimpleCacheManager> genericCacheManagerCustomizer() {
|
||||
return new CacheManagerTestCustomizer<>() {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
CacheManagerCustomizer<CouchbaseCacheManager> couchbaseCacheManagerCustomizer() {
|
||||
return new CacheManagerTestCustomizer<>() {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
CacheManagerCustomizer<RedisCacheManager> redisCacheManagerCustomizer() {
|
||||
return new CacheManagerTestCustomizer<>() {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
CacheManagerCustomizer<HazelcastCacheManager> hazelcastCacheManagerCustomizer() {
|
||||
return new CacheManagerTestCustomizer<>() {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
CacheManagerCustomizer<SpringEmbeddedCacheManager> infinispanCacheManagerCustomizer() {
|
||||
return new CacheManagerTestCustomizer<>() {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
CacheManagerCustomizer<SpringCache2kCacheManager> cache2kCacheManagerCustomizer() {
|
||||
return new CacheManagerTestCustomizer<>() {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
CacheManagerCustomizer<CaffeineCacheManager> caffeineCacheManagerCustomizer() {
|
||||
return new CacheManagerTestCustomizer<>() {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract static class CacheManagerTestCustomizer<T extends CacheManager> implements CacheManagerCustomizer<T> {
|
||||
|
||||
T cacheManager;
|
||||
|
||||
@Override
|
||||
public void customize(T cacheManager) {
|
||||
if (this.cacheManager != null) {
|
||||
throw new IllegalStateException("Customized invoked twice");
|
||||
}
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.caffeine.CaffeineCacheManager;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class CacheManagerCustomizersTests {
|
||||
|
||||
@Test
|
||||
void customizeWithNullCustomizersShouldDoNothing() {
|
||||
new CacheManagerCustomizers(null).customize(mock(CacheManager.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void customizeSimpleCacheManager() {
|
||||
CacheManagerCustomizers customizers = new CacheManagerCustomizers(
|
||||
Collections.singletonList(new CacheNamesCacheManagerCustomizer()));
|
||||
ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
|
||||
customizers.customize(cacheManager);
|
||||
assertThat(cacheManager.getCacheNames()).containsOnly("one", "two");
|
||||
}
|
||||
|
||||
@Test
|
||||
void customizeShouldCheckGeneric() {
|
||||
List<TestCustomizer<?>> list = new ArrayList<>();
|
||||
list.add(new TestCustomizer<>());
|
||||
list.add(new TestConcurrentMapCacheManagerCustomizer());
|
||||
CacheManagerCustomizers customizers = new CacheManagerCustomizers(list);
|
||||
customizers.customize(mock(CacheManager.class));
|
||||
assertThat(list.get(0).getCount()).isOne();
|
||||
assertThat(list.get(1).getCount()).isZero();
|
||||
customizers.customize(mock(ConcurrentMapCacheManager.class));
|
||||
assertThat(list.get(0).getCount()).isEqualTo(2);
|
||||
assertThat(list.get(1).getCount()).isOne();
|
||||
customizers.customize(mock(CaffeineCacheManager.class));
|
||||
assertThat(list.get(0).getCount()).isEqualTo(3);
|
||||
assertThat(list.get(1).getCount()).isOne();
|
||||
}
|
||||
|
||||
static class CacheNamesCacheManagerCustomizer implements CacheManagerCustomizer<ConcurrentMapCacheManager> {
|
||||
|
||||
@Override
|
||||
public void customize(ConcurrentMapCacheManager cacheManager) {
|
||||
cacheManager.setCacheNames(Arrays.asList("one", "two"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestCustomizer<T extends CacheManager> implements CacheManagerCustomizer<T> {
|
||||
|
||||
private int count;
|
||||
|
||||
@Override
|
||||
public void customize(T cacheManager) {
|
||||
this.count++;
|
||||
}
|
||||
|
||||
int getCount() {
|
||||
return this.count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestConcurrentMapCacheManagerCustomizer extends TestCustomizer<ConcurrentMapCacheManager> {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cache.autoconfigure;
|
||||
|
||||
import org.ehcache.jsr107.EhcacheCachingProvider;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.cache.autoconfigure.CacheAutoConfigurationTests.DefaultCacheConfiguration;
|
||||
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
|
||||
import org.springframework.boot.testsupport.classpath.resources.WithResource;
|
||||
import org.springframework.cache.jcache.JCacheCacheManager;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link CacheAutoConfiguration} with EhCache 3.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@ClassPathExclusions("ehcache-2*.jar")
|
||||
class EhCache3CacheAutoConfigurationTests extends AbstractCacheAutoConfigurationTests {
|
||||
|
||||
@Test
|
||||
void ehcache3AsJCacheWithCaches() {
|
||||
String cachingProviderFqn = EhcacheCachingProvider.class.getName();
|
||||
this.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)
|
||||
.withPropertyValues("spring.cache.type=jcache", "spring.cache.jcache.provider=" + cachingProviderFqn,
|
||||
"spring.cache.cacheNames[0]=foo", "spring.cache.cacheNames[1]=bar")
|
||||
.run((context) -> {
|
||||
JCacheCacheManager cacheManager = getCacheManager(context, JCacheCacheManager.class);
|
||||
assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithResource(name = "ehcache3.xml", content = """
|
||||
<config
|
||||
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
|
||||
xmlns='http://www.ehcache.org/v3'
|
||||
xmlns:jsr107='http://www.ehcache.org/v3/jsr107'
|
||||
xsi:schemaLocation="
|
||||
http://www.ehcache.org/v3 https://www.ehcache.org/schema/ehcache-core-3.10.xsd
|
||||
http://www.ehcache.org/v3/jsr107 https://www.ehcache.org/schema/ehcache-107-ext-3.10.xsd">
|
||||
|
||||
<cache-template name="example">
|
||||
<heap unit="entries">200</heap>
|
||||
</cache-template>
|
||||
|
||||
<cache alias="foo" uses-template="example">
|
||||
<expiry>
|
||||
<ttl unit="seconds">600</ttl>
|
||||
</expiry>
|
||||
<jsr107:mbeans enable-statistics="true"/>
|
||||
</cache>
|
||||
|
||||
<cache alias="bar" uses-template="example">
|
||||
<expiry>
|
||||
<ttl unit="seconds">400</ttl>
|
||||
</expiry>
|
||||
</cache>
|
||||
|
||||
</config>
|
||||
""")
|
||||
void ehcache3AsJCacheWithConfig() {
|
||||
String cachingProviderFqn = EhcacheCachingProvider.class.getName();
|
||||
String configLocation = "ehcache3.xml";
|
||||
this.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)
|
||||
.withPropertyValues("spring.cache.type=jcache", "spring.cache.jcache.provider=" + cachingProviderFqn,
|
||||
"spring.cache.jcache.config=" + configLocation)
|
||||
.run((context) -> {
|
||||
JCacheCacheManager cacheManager = getCacheManager(context, JCacheCacheManager.class);
|
||||
|
||||
Resource configResource = new ClassPathResource(configLocation);
|
||||
assertThat(cacheManager.getCacheManager().getURI()).isEqualTo(configResource.getURI());
|
||||
assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#
|
||||
# Test JSR 107 provider for testing purposes only.
|
||||
#
|
||||
org.springframework.boot.autoconfigure.cache.support.MockCachingProvider
|
||||
@@ -0,0 +1,19 @@
|
||||
<hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-5.0.xsd"
|
||||
xmlns="http://www.hazelcast.com/schema/config"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<queue name="foobar"/>
|
||||
|
||||
<map name="foobar">
|
||||
<time-to-live-seconds>3600</time-to-live-seconds>
|
||||
<max-idle-seconds>600</max-idle-seconds>
|
||||
</map>
|
||||
|
||||
<network>
|
||||
<join>
|
||||
<auto-detection enabled="false" />
|
||||
<multicast enabled="false"/>
|
||||
</join>
|
||||
</network>
|
||||
|
||||
</hazelcast>
|
||||
Reference in New Issue
Block a user