Support customization of CacheManager

This commit allows to customize the auto-configured `CacheManager` by
exposing a bean of type `CacheManagerCustomizer`. The implementation may
reference the type of a `CacheManager` to determine in which case it has
to be invoked.

Several implementations can be provided and ordered using the regular
`Ordered` interface and `@Order` annotation.

Closes gh-5039
This commit is contained in:
Stephane Nicoll 2016-02-24 11:38:05 +01:00
parent ce71bd997c
commit 5febd497da
14 changed files with 445 additions and 17 deletions

View File

@ -66,7 +66,7 @@ import org.springframework.util.Assert;
@EnableConfigurationProperties(CacheProperties.class)
@AutoConfigureBefore(HibernateJpaAutoConfiguration.class)
@AutoConfigureAfter({ HazelcastAutoConfiguration.class, RedisAutoConfiguration.class })
@Import(CacheConfigurationImportSelector.class)
@Import({ CacheManagerCustomizerInvoker.class, CacheConfigurationImportSelector.class })
public class CacheAutoConfiguration {
static final String VALIDATOR_BEAN_NAME = "cacheAutoConfigurationValidator";

View File

@ -0,0 +1,36 @@
/*
* Copyright 2012-2016 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
*
* http://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.autoconfigure.cache;
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.
*
* @author Stephane Nicoll
* @since 1.3.3
*/
public interface CacheManagerCustomizer<C extends CacheManager> {
/**
* Customize the cache manager.
* @param cacheManager the {@code CacheManager} to customize
*/
void customize(C cacheManager);
}

View File

@ -0,0 +1,84 @@
/*
* Copyright 2012-2016 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
*
* http://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.autoconfigure.cache;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.cache.CacheManager;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
/**
* Invoke the available {@link CacheManagerCustomizer} instances in the context for a
* given {@link CacheManager}.
*
* @author Stephane Nicoll
*/
class CacheManagerCustomizerInvoker implements ApplicationContextAware {
private ConfigurableApplicationContext applicationContext;
/**
* 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 cacheManager the cache manager to customize
*/
public void customize(CacheManager cacheManager) {
List<CacheManagerCustomizer<CacheManager>> customizers = findCustomizers(cacheManager);
AnnotationAwareOrderComparator.sort(customizers);
for (CacheManagerCustomizer<CacheManager> customizer : customizers) {
customizer.customize(cacheManager);
}
}
@SuppressWarnings("unchecked")
private List<CacheManagerCustomizer<CacheManager>> findCustomizers(CacheManager cacheManager) {
if (this.applicationContext == null) {
return Collections.emptyList();
}
Map<String, CacheManagerCustomizer> map = BeanFactoryUtils
.beansOfTypeIncludingAncestors(this.applicationContext.getBeanFactory(), CacheManagerCustomizer.class);
List<CacheManagerCustomizer<CacheManager>> customizers
= new ArrayList<CacheManagerCustomizer<CacheManager>>();
for (CacheManagerCustomizer customizer : map.values()) {
Class<?> target = GenericTypeResolver.resolveTypeArgument(
customizer.getClass(), CacheManagerCustomizer.class);
if (target == null || target.isAssignableFrom(cacheManager.getClass())) {
customizers.add(customizer);
}
}
return customizers;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (applicationContext instanceof ConfigurableApplicationContext) {
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
}
}
}

View File

@ -48,9 +48,14 @@ class EhCacheCacheConfiguration {
@Autowired
private CacheProperties cacheProperties;
@Autowired
CacheManagerCustomizerInvoker customizerInvoker;
@Bean
public EhCacheCacheManager cacheManager(CacheManager ehCacheCacheManager) {
return new EhCacheCacheManager(ehCacheCacheManager);
EhCacheCacheManager cacheManager = new EhCacheCacheManager(ehCacheCacheManager);
this.customizerInvoker.customize(cacheManager);
return cacheManager;
}
@Bean

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* Copyright 2012-2016 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.
@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.cache;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cache.Cache;
@ -40,10 +41,14 @@ import org.springframework.context.annotation.Configuration;
@Conditional(CacheCondition.class)
class GenericCacheConfiguration {
@Autowired
CacheManagerCustomizerInvoker customizerInvoker;
@Bean
public SimpleCacheManager cacheManager(Collection<Cache> caches) {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(caches);
this.customizerInvoker.customize(cacheManager);
return cacheManager;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* Copyright 2012-2016 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.
@ -48,6 +48,9 @@ class GuavaCacheConfiguration {
@Autowired
private CacheProperties cacheProperties;
@Autowired
CacheManagerCustomizerInvoker customizerInvoker;
@Autowired(required = false)
private CacheBuilder<Object, Object> cacheBuilder;
@ -64,6 +67,7 @@ class GuavaCacheConfiguration {
if (!CollectionUtils.isEmpty(cacheNames)) {
cacheManager.setCacheNames(cacheNames);
}
this.customizerInvoker.customize(cacheManager);
return cacheManager;
}

View File

@ -48,6 +48,9 @@ abstract class HazelcastInstanceConfiguration {
@Autowired
private CacheProperties cacheProperties;
@Autowired
CacheManagerCustomizerInvoker customizerInvoker;
@Bean
public HazelcastCacheManager cacheManager(
HazelcastInstance existingHazelcastInstance) throws IOException {
@ -58,7 +61,9 @@ abstract class HazelcastInstanceConfiguration {
location).getHazelcastInstance();
return new CloseableHazelcastCacheManager(cacheHazelcastInstance);
}
return new HazelcastCacheManager(existingHazelcastInstance);
HazelcastCacheManager cacheManager = new HazelcastCacheManager(existingHazelcastInstance);
this.customizerInvoker.customize(cacheManager);
return cacheManager;
}
}
@ -70,6 +75,9 @@ abstract class HazelcastInstanceConfiguration {
@Autowired
private CacheProperties cacheProperties;
@Autowired
CacheManagerCustomizerInvoker customizerInvoker;
@Bean
public HazelcastInstance hazelcastInstance() throws IOException {
Resource config = this.cacheProperties.getHazelcast().getConfig();
@ -82,7 +90,9 @@ abstract class HazelcastInstanceConfiguration {
@Bean
public HazelcastCacheManager cacheManager() throws IOException {
return new HazelcastCacheManager(hazelcastInstance());
HazelcastCacheManager cacheManager = new HazelcastCacheManager(hazelcastInstance());
this.customizerInvoker.customize(cacheManager);
return cacheManager;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* Copyright 2012-2016 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.
@ -51,13 +51,18 @@ public class InfinispanCacheConfiguration {
@Autowired
private CacheProperties cacheProperties;
@Autowired
CacheManagerCustomizerInvoker customizerInvoker;
@Autowired(required = false)
private ConfigurationBuilder defaultConfigurationBuilder;
@Bean
public SpringEmbeddedCacheManager cacheManager(
EmbeddedCacheManager embeddedCacheManager) {
return new SpringEmbeddedCacheManager(embeddedCacheManager);
SpringEmbeddedCacheManager cacheManager = new SpringEmbeddedCacheManager(embeddedCacheManager);
this.customizerInvoker.customize(cacheManager);
return cacheManager;
}
@Bean(destroyMethod = "stop")

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* Copyright 2012-2016 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.
@ -63,6 +63,9 @@ class JCacheCacheConfiguration {
@Autowired
private CacheProperties cacheProperties;
@Autowired
CacheManagerCustomizerInvoker customizerInvoker;
@Autowired(required = false)
private javax.cache.configuration.Configuration<?, ?> defaultCacheConfiguration;
@ -71,7 +74,9 @@ class JCacheCacheConfiguration {
@Bean
public JCacheCacheManager cacheManager(CacheManager jCacheCacheManager) {
return new JCacheCacheManager(jCacheCacheManager);
JCacheCacheManager cacheManager = new JCacheCacheManager(jCacheCacheManager);
this.customizerInvoker.customize(cacheManager);
return cacheManager;
}
@Bean

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* Copyright 2012-2016 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.
@ -46,6 +46,9 @@ class RedisCacheConfiguration {
@Autowired
private CacheProperties cacheProperties;
@Autowired
CacheManagerCustomizerInvoker customizerInvoker;
@Bean
public RedisCacheManager cacheManager(RedisTemplate<Object, Object> redisTemplate) {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
@ -53,6 +56,7 @@ class RedisCacheConfiguration {
if (!cacheNames.isEmpty()) {
cacheManager.setCacheNames(cacheNames);
}
this.customizerInvoker.customize(cacheManager);
return cacheManager;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* Copyright 2012-2016 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.
@ -40,6 +40,9 @@ class SimpleCacheConfiguration {
@Autowired
private CacheProperties cacheProperties;
@Autowired
CacheManagerCustomizerInvoker customizerInvoker;
@Bean
public ConcurrentMapCacheManager cacheManager() {
ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
@ -47,6 +50,7 @@ class SimpleCacheConfiguration {
if (!cacheNames.isEmpty()) {
cacheManager.setCacheNames(cacheNames);
}
this.customizerInvoker.customize(cacheManager);
return cacheManager;
}

View File

@ -17,8 +17,12 @@
package org.springframework.boot.autoconfigure.cache;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.cache.configuration.CompleteConfiguration;
import javax.cache.configuration.MutableConfiguration;
@ -70,6 +74,7 @@ import org.springframework.data.redis.core.RedisTemplate;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.CoreMatchers.sameInstance;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
@ -150,6 +155,12 @@ public class CacheAutoConfigurationTests {
assertThat(cacheManager.getCacheNames(), empty());
}
@Test
public void simpleCacheWithCustomizers() {
testCustomizers(DefaultCacheAndCustomizersConfiguration.class, "simple",
"allCacheManagerCustomizer", "simpleCacheManagerCustomizer");
}
@Test
public void simpleCacheExplicitWithCacheNames() {
load(DefaultCacheConfiguration.class, "spring.cache.type=simple",
@ -179,6 +190,12 @@ public class CacheAutoConfigurationTests {
load(DefaultCacheConfiguration.class, "spring.cache.type=generic");
}
@Test
public void genericCacheWithCustomizers() {
testCustomizers(GenericCacheAndCustomizersConfiguration.class, "generic",
"allCacheManagerCustomizer", "genericCacheManagerCustomizer");
}
@Test
public void genericCacheExplicitWithCaches() {
load(GenericCacheConfiguration.class, "spring.cache.type=generic");
@ -197,6 +214,12 @@ public class CacheAutoConfigurationTests {
assertThat(cacheManager.getCacheNames(), empty());
}
@Test
public void redisCacheWithCustomizers() {
testCustomizers(RedisCacheAndCustomizersConfiguration.class, "redis",
"allCacheManagerCustomizer", "redisCacheManagerCustomizer");
}
@Test
public void redisCacheExplicitWithCaches() {
load(RedisCacheConfiguration.class, "spring.cache.type=redis",
@ -315,6 +338,12 @@ public class CacheAutoConfigurationTests {
equalTo(cacheManager.getCacheManager()));
}
@Test
public void ehCacheCacheWithCustomizers() {
testCustomizers(DefaultCacheAndCustomizersConfiguration.class, "ehcache",
"allCacheManagerCustomizer", "ehCacheCacheManagerCustomizer");
}
@Test
public void ehCacheCacheWithConfig() {
load(DefaultCacheConfiguration.class, "spring.cache.type=ehcache",
@ -348,6 +377,12 @@ public class CacheAutoConfigurationTests {
equalTo(getHazelcastInstance(cacheManager)));
}
@Test
public void hazelcastCacheWithCustomizers() {
testCustomizers(DefaultCacheAndCustomizersConfiguration.class, "hazelcast",
"allCacheManagerCustomizer", "hazelcastCacheManagerCustomizer");
}
@Test
public void hazelcastCacheWithConfig() throws IOException {
load(DefaultCacheConfiguration.class, "spring.cache.type=hazelcast",
@ -461,6 +496,12 @@ public class CacheAutoConfigurationTests {
assertThat(cacheManager.getCacheNames(), containsInAnyOrder("foo", "bar"));
}
@Test
public void infinispanCacheWithCustomizers() {
testCustomizers(DefaultCacheAndCustomizersConfiguration.class, "infinispan",
"allCacheManagerCustomizer", "infinispanCacheManagerCustomizer");
}
@Test
public void infinispanCacheWithCaches() {
load(DefaultCacheConfiguration.class, "spring.cache.type=infinispan",
@ -533,6 +574,12 @@ public class CacheAutoConfigurationTests {
assertThat(((GuavaCache) foo).getNativeCache().stats().missCount(), equalTo(0L));
}
@Test
public void guavaCacheWithCustomizers() {
testCustomizers(DefaultCacheAndCustomizersConfiguration.class, "guava",
"allCacheManagerCustomizer", "guavaCacheManagerCustomizer");
}
@Test
public void guavaCacheExplicitWithSpec() {
load(DefaultCacheConfiguration.class, "spring.cache.type=guava",
@ -563,6 +610,28 @@ public class CacheAutoConfigurationTests {
return type.cast(cacheManager);
}
private void testCustomizers(Class<?> config, String cacheType, String... expectedCustomizerNames) {
load(config, "spring.cache.type=" + cacheType);
CacheManager cacheManager = validateCacheManager(CacheManager.class);
List<String> expected = new ArrayList<String>();
expected.addAll(Arrays.asList(expectedCustomizerNames));
Map<String, CacheManagerTestCustomizer> map =
this.context.getBeansOfType(CacheManagerTestCustomizer.class);
for (Map.Entry<String, CacheManagerTestCustomizer> entry : map.entrySet()) {
if (expected.contains(entry.getKey())) {
expected.remove(entry.getKey());
assertThat("Customizer with name " + entry.getKey() + " should have been " +
"invoked", entry.getValue().cacheManager, sameInstance(cacheManager));
}
else {
assertThat("Customizer with name " + entry.getKey() + " should not have been" +
"invoked", entry.getValue().cacheManager, nullValue());
}
}
assertThat("The following customizers should have been invoked: " + expected,
expected, hasSize(0));
}
private void load(Class<?> config, String... environment) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(applicationContext, environment);
@ -588,6 +657,13 @@ public class CacheAutoConfigurationTests {
}
@Configuration
@EnableCaching
@Import(CacheManagerCustomizersConfiguration.class)
static class DefaultCacheAndCustomizersConfiguration {
}
@Configuration
@EnableCaching
static class GenericCacheConfiguration {
@ -604,6 +680,11 @@ public class CacheAutoConfigurationTests {
}
@Configuration
@Import({GenericCacheConfiguration.class, CacheManagerCustomizersConfiguration.class})
static class GenericCacheAndCustomizersConfiguration {
}
@Configuration
@EnableCaching
static class RedisCacheConfiguration {
@ -615,6 +696,12 @@ public class CacheAutoConfigurationTests {
}
@Configuration
@Import({RedisCacheConfiguration.class, CacheManagerCustomizersConfiguration.class})
static class RedisCacheAndCustomizersConfiguration {
}
@Configuration
@EnableCaching
static class JCacheCustomConfiguration {
@ -688,8 +775,8 @@ public class CacheAutoConfigurationTests {
}
@Configuration
@ImportAutoConfiguration({ CacheAutoConfiguration.class,
HazelcastAutoConfiguration.class })
@ImportAutoConfiguration({CacheAutoConfiguration.class,
HazelcastAutoConfiguration.class})
static class HazelcastAndCacheConfiguration {
}
@ -708,7 +795,7 @@ public class CacheAutoConfigurationTests {
}
@Configuration
@Import({ GenericCacheConfiguration.class, RedisCacheConfiguration.class })
@Import({GenericCacheConfiguration.class, RedisCacheConfiguration.class})
static class CustomCacheManagerConfiguration {
@Bean
@ -719,7 +806,7 @@ public class CacheAutoConfigurationTests {
}
@Configuration
@Import({ GenericCacheConfiguration.class, RedisCacheConfiguration.class })
@Import({GenericCacheConfiguration.class, RedisCacheConfiguration.class})
static class CustomCacheManagerFromSupportConfiguration
extends CachingConfigurerSupport {
@ -744,7 +831,7 @@ public class CacheAutoConfigurationTests {
}
@Configuration
@Import({ GenericCacheConfiguration.class, RedisCacheConfiguration.class })
@Import({GenericCacheConfiguration.class, RedisCacheConfiguration.class})
static class CustomCacheResolverConfiguration extends CachingConfigurerSupport {
@Override
@ -765,4 +852,64 @@ public class CacheAutoConfigurationTests {
}
@Configuration
static class CacheManagerCustomizersConfiguration {
@Bean
public CacheManagerCustomizer<CacheManager> allCacheManagerCustomizer() {
return new CacheManagerTestCustomizer<CacheManager>() {
};
}
@Bean
public CacheManagerCustomizer<ConcurrentMapCacheManager> simpleCacheManagerCustomizer() {
return new CacheManagerTestCustomizer<ConcurrentMapCacheManager>() {
};
}
@Bean
public CacheManagerCustomizer<SimpleCacheManager> genericCacheManagerCustomizer() {
return new CacheManagerTestCustomizer<SimpleCacheManager>() { };
}
@Bean
public CacheManagerCustomizer<RedisCacheManager> redisCacheManagerCustomizer() {
return new CacheManagerTestCustomizer<RedisCacheManager>() { };
}
@Bean
public CacheManagerCustomizer<EhCacheCacheManager> ehCacheCacheManagerCustomizer() {
return new CacheManagerTestCustomizer<EhCacheCacheManager>() { };
}
@Bean
public CacheManagerCustomizer<HazelcastCacheManager> hazelcastCacheManagerCustomizer() {
return new CacheManagerTestCustomizer<HazelcastCacheManager>() { };
}
@Bean
public CacheManagerCustomizer<SpringEmbeddedCacheManager> infinispanCacheManagerCustomizer() {
return new CacheManagerTestCustomizer<SpringEmbeddedCacheManager>() { };
}
@Bean
public CacheManagerCustomizer<GuavaCacheManager> guavaCacheManagerCustomizer() {
return new CacheManagerTestCustomizer<GuavaCacheManager>() { };
}
}
static abstract class CacheManagerTestCustomizer<C extends CacheManager> implements CacheManagerCustomizer<C> {
private C cacheManager;
@Override
public void customize(C cacheManager) {
if (this.cacheManager != null) {
throw new IllegalStateException("Customized invoked twice");
}
this.cacheManager = cacheManager;
}
}
}

View File

@ -0,0 +1,96 @@
/*
* Copyright 2012-2016 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
*
* http://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.autoconfigure.cache;
import java.util.Arrays;
import org.junit.After;
import org.junit.Test;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyZeroInteractions;
/**
*
* @author Stephane Nicoll
*/
public class CacheManagerCustomizerInvokerTests {
private AnnotationConfigApplicationContext context;
@After
public void tearDown() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void customizeSimpleCacheManager() {
load(SimpleConfiguration.class, "spring.cache.type=simple");
ConcurrentMapCacheManager cacheManager = this.context.getBean(ConcurrentMapCacheManager.class);
assertThat(cacheManager.getCacheNames(), containsInAnyOrder("one", "two"));
assertThat(cacheManager.getCacheNames(), hasSize(2));
}
@Test
public void customizeNoConfigurableApplicationContext() {
CacheManagerCustomizerInvoker invoker = new CacheManagerCustomizerInvoker();
ApplicationContext context = mock(ApplicationContext.class);
invoker.setApplicationContext(context);
invoker.customize(mock(CacheManager.class));
verifyZeroInteractions(context);
}
private void load(Class<?> config, String... environment) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(applicationContext, environment);
applicationContext.register(config);
applicationContext.register(CacheAutoConfiguration.class);
applicationContext.refresh();
this.context = applicationContext;
}
@Configuration
@EnableCaching
static class SimpleConfiguration {
@Bean
public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {
return new CacheManagerCustomizer<ConcurrentMapCacheManager>() {
@Override
public void customize(ConcurrentMapCacheManager cacheManager) {
cacheManager.setCacheNames(Arrays.asList("one", "two"));
}
};
}
}
}

View File

@ -3184,6 +3184,29 @@ Spring Boot tries to detect the following providers (in this order):
It is also possible to _force_ the cache provider to use via the `spring.cache.type`
property.
If the `CacheManager` is auto-configured by Spring Boot, you can further tune its
configuration before it is fully initialized by exposing a bean implementing the
`CacheManagerCustomizer` interface. The following set the cache names to use.
[source,java,indent=0]
----
@Bean
public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {
return new CacheManagerCustomizer<ConcurrentMapCacheManager>() {
@Override
public void customize(ConcurrentMapCacheManager cacheManager) {
cacheManager.setCacheNames(Arrays.asList("one", "two"));
}
};
}
----
[NOTE]
===
In the example above, a `ConcurrentMapCacheManager` is expected to be configured. If that
is not the case, the customizer won't be invoked at all. You can have as many customizers
as you want and you can also order them as usual using `@Order` or `Ordered`.
===
[[boot-features-caching-provider-generic]]