Merge branch '1.3.x'

This commit is contained in:
Stephane Nicoll
2016-02-24 14:09:07 +01:00
14 changed files with 438 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;
@@ -140,6 +144,12 @@ public class CacheAutoConfigurationTests {
assertThat(cacheManager.getCacheNames()).isEmpty();
}
@Test
public void simpleCacheWithCustomizers() {
testCustomizers(DefaultCacheAndCustomizersConfiguration.class, "simple",
"allCacheManagerCustomizer", "simpleCacheManagerCustomizer");
}
@Test
public void simpleCacheExplicitWithCacheNames() {
load(DefaultCacheConfiguration.class, "spring.cache.type=simple",
@@ -168,6 +178,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");
@@ -186,6 +202,12 @@ public class CacheAutoConfigurationTests {
assertThat(cacheManager.getCacheNames()).isEmpty();
}
@Test
public void redisCacheWithCustomizers() {
testCustomizers(RedisCacheAndCustomizersConfiguration.class, "redis",
"allCacheManagerCustomizer", "redisCacheManagerCustomizer");
}
@Test
public void redisCacheExplicitWithCaches() {
load(RedisCacheConfiguration.class, "spring.cache.type=redis",
@@ -298,6 +320,12 @@ public class CacheAutoConfigurationTests {
.isEqualTo(cacheManager.getCacheManager());
}
@Test
public void ehCacheCacheWithCustomizers() {
testCustomizers(DefaultCacheAndCustomizersConfiguration.class, "ehcache",
"allCacheManagerCustomizer", "ehCacheCacheManagerCustomizer");
}
@Test
public void ehCacheCacheWithConfig() {
load(DefaultCacheConfiguration.class, "spring.cache.type=ehcache",
@@ -329,6 +357,12 @@ public class CacheAutoConfigurationTests {
.isEqualTo(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",
@@ -441,6 +475,12 @@ public class CacheAutoConfigurationTests {
assertThat(cacheManager.getCacheNames()).contains("foo", "bar");
}
@Test
public void infinispanCacheWithCustomizers() {
testCustomizers(DefaultCacheAndCustomizersConfiguration.class, "infinispan",
"allCacheManagerCustomizer", "infinispanCacheManagerCustomizer");
}
@Test
public void infinispanCacheWithCaches() {
load(DefaultCacheConfiguration.class, "spring.cache.type=infinispan",
@@ -508,6 +548,12 @@ public class CacheAutoConfigurationTests {
assertThat(((GuavaCache) foo).getNativeCache().stats().missCount()).isEqualTo(0L);
}
@Test
public void guavaCacheWithCustomizers() {
testCustomizers(DefaultCacheAndCustomizersConfiguration.class, "guava",
"allCacheManagerCustomizer", "guavaCacheManagerCustomizer");
}
@Test
public void guavaCacheExplicitWithSpec() {
load(DefaultCacheConfiguration.class, "spring.cache.type=guava",
@@ -537,6 +583,25 @@ 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(entry.getValue().cacheManager).isSameAs(cacheManager);
}
else {
assertThat(entry.getValue().cacheManager).isNull();
}
}
assertThat(expected).hasSize(0);
}
private void load(Class<?> config, String... environment) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(applicationContext, environment);
@@ -562,6 +627,13 @@ public class CacheAutoConfigurationTests {
}
@Configuration
@EnableCaching
@Import(CacheManagerCustomizersConfiguration.class)
static class DefaultCacheAndCustomizersConfiguration {
}
@Configuration
@EnableCaching
static class GenericCacheConfiguration {
@@ -578,6 +650,11 @@ public class CacheAutoConfigurationTests {
}
@Configuration
@Import({GenericCacheConfiguration.class, CacheManagerCustomizersConfiguration.class})
static class GenericCacheAndCustomizersConfiguration {
}
@Configuration
@EnableCaching
static class RedisCacheConfiguration {
@@ -589,6 +666,12 @@ public class CacheAutoConfigurationTests {
}
@Configuration
@Import({RedisCacheConfiguration.class, CacheManagerCustomizersConfiguration.class})
static class RedisCacheAndCustomizersConfiguration {
}
@Configuration
@EnableCaching
static class JCacheCustomConfiguration {
@@ -662,8 +745,8 @@ public class CacheAutoConfigurationTests {
}
@Configuration
@ImportAutoConfiguration({ CacheAutoConfiguration.class,
HazelcastAutoConfiguration.class })
@ImportAutoConfiguration({CacheAutoConfiguration.class,
HazelcastAutoConfiguration.class})
static class HazelcastAndCacheConfiguration {
}
@@ -682,7 +765,7 @@ public class CacheAutoConfigurationTests {
}
@Configuration
@Import({ GenericCacheConfiguration.class, RedisCacheConfiguration.class })
@Import({GenericCacheConfiguration.class, RedisCacheConfiguration.class})
static class CustomCacheManagerConfiguration {
@Bean
@@ -693,7 +776,7 @@ public class CacheAutoConfigurationTests {
}
@Configuration
@Import({ GenericCacheConfiguration.class, RedisCacheConfiguration.class })
@Import({GenericCacheConfiguration.class, RedisCacheConfiguration.class})
static class CustomCacheManagerFromSupportConfiguration
extends CachingConfigurerSupport {
@@ -718,7 +801,7 @@ public class CacheAutoConfigurationTests {
}
@Configuration
@Import({ GenericCacheConfiguration.class, RedisCacheConfiguration.class })
@Import({GenericCacheConfiguration.class, RedisCacheConfiguration.class})
static class CustomCacheResolverConfiguration extends CachingConfigurerSupport {
@Override
@@ -739,4 +822,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,93 @@
/*
* 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.assertj.core.api.Assertions.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()).containsOnly("one", "two");
}
@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"));
}
};
}
}
}