Skip to content

Commit 1314aaa

Browse files
committed
Avoid early init of CacheManager
This commit restructures the Cache auto-configuration to avoid an early init on CacheManager (and potentially all its infrastructure). Rather than adding a dependency on the validator bean, this commit relies on the fact CacheAspectSupport checks if a CacheManager is available in the afterSingletonsInstantiated callback. In this case, a simple bean with a postconstruct callback is enough. Closes gh-13038
1 parent 7392c57 commit 1314aaa

File tree

2 files changed

+65
-57
lines changed

2 files changed

+65
-57
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfiguration.java

Lines changed: 18 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2016 the original author or authors.
2+
* Copyright 2012-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,14 +18,8 @@
1818

1919
import java.util.List;
2020

21-
import javax.annotation.PostConstruct;
22-
23-
import org.springframework.beans.BeansException;
21+
import org.springframework.beans.factory.InitializingBean;
2422
import org.springframework.beans.factory.ObjectProvider;
25-
import org.springframework.beans.factory.annotation.Autowired;
26-
import org.springframework.beans.factory.config.BeanDefinition;
27-
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
28-
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
2923
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
3024
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
3125
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@@ -46,7 +40,6 @@
4640
import org.springframework.context.annotation.Configuration;
4741
import org.springframework.context.annotation.Import;
4842
import org.springframework.context.annotation.ImportSelector;
49-
import org.springframework.context.annotation.Role;
5043
import org.springframework.core.type.AnnotationMetadata;
5144
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
5245
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@@ -73,8 +66,6 @@
7366
@Import(CacheConfigurationImportSelector.class)
7467
public class CacheAutoConfiguration {
7568

76-
static final String VALIDATOR_BEAN_NAME = "cacheAutoConfigurationValidator";
77-
7869
@Bean
7970
@ConditionalOnMissingBean
8071
public CacheManagerCustomizers cacheManagerCustomizers(
@@ -83,14 +74,10 @@ public CacheManagerCustomizers cacheManagerCustomizers(
8374
}
8475

8576
@Bean
86-
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
87-
public static CacheManagerValidatorPostProcessor cacheAutoConfigurationValidatorPostProcessor() {
88-
return new CacheManagerValidatorPostProcessor();
89-
}
90-
91-
@Bean(name = VALIDATOR_BEAN_NAME)
92-
public CacheManagerValidator cacheAutoConfigurationValidator() {
93-
return new CacheManagerValidator();
77+
public CacheManagerValidator cacheAutoConfigurationValidator(
78+
CacheProperties cacheProperties,
79+
ObjectProvider<CacheManager> cacheManager) {
80+
return new CacheManagerValidator(cacheProperties, cacheManager);
9481
}
9582

9683
@Configuration
@@ -105,50 +92,25 @@ public CacheManagerJpaDependencyConfiguration() {
10592

10693
}
10794

108-
/**
109-
* {@link BeanFactoryPostProcessor} to ensure that the {@link CacheManagerValidator}
110-
* is triggered before {@link CacheAspectSupport} but without causing early
111-
* instantiation.
112-
*/
113-
static class CacheManagerValidatorPostProcessor implements BeanFactoryPostProcessor {
114-
115-
@Override
116-
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
117-
throws BeansException {
118-
for (String name : beanFactory.getBeanNamesForType(CacheAspectSupport.class,
119-
false, false)) {
120-
BeanDefinition definition = beanFactory.getBeanDefinition(name);
121-
definition.setDependsOn(
122-
append(definition.getDependsOn(), VALIDATOR_BEAN_NAME));
123-
}
124-
}
125-
126-
private String[] append(String[] array, String value) {
127-
String[] result = new String[array != null ? array.length + 1 : 1];
128-
if (array != null) {
129-
System.arraycopy(array, 0, result, 0, array.length);
130-
}
131-
result[result.length - 1] = value;
132-
return result;
133-
}
134-
135-
}
136-
13795
/**
13896
* Bean used to validate that a CacheManager exists and provide a more meaningful
13997
* exception.
14098
*/
141-
static class CacheManagerValidator {
99+
static class CacheManagerValidator implements InitializingBean {
100+
101+
private final CacheProperties cacheProperties;
142102

143-
@Autowired
144-
private CacheProperties cacheProperties;
103+
private final ObjectProvider<CacheManager> cacheManager;
145104

146-
@Autowired(required = false)
147-
private CacheManager cacheManager;
105+
CacheManagerValidator(CacheProperties cacheProperties,
106+
ObjectProvider<CacheManager> cacheManager) {
107+
this.cacheProperties = cacheProperties;
108+
this.cacheManager = cacheManager;
109+
}
148110

149-
@PostConstruct
150-
public void checkHasCacheManager() {
151-
Assert.notNull(this.cacheManager,
111+
@Override
112+
public void afterPropertiesSet() {
113+
Assert.notNull(this.cacheManager.getIfAvailable(),
152114
"No cache manager could "
153115
+ "be auto-configured, check your configuration (caching "
154116
+ "type is '" + this.cacheProperties.getType() + "')");

spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2017 the original author or authors.
2+
* Copyright 2012-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -51,9 +51,11 @@
5151
import org.junit.Test;
5252
import org.junit.rules.ExpectedException;
5353

54+
import org.springframework.beans.BeansException;
5455
import org.springframework.beans.DirectFieldAccessor;
5556
import org.springframework.beans.factory.BeanCreationException;
5657
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
58+
import org.springframework.beans.factory.config.BeanPostProcessor;
5759
import org.springframework.boot.autoconfigure.cache.support.MockCachingProvider;
5860
import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration;
5961
import org.springframework.boot.test.util.EnvironmentTestUtils;
@@ -770,6 +772,17 @@ public void caffeineCacheExplicitWithSpecString() {
770772
validateCaffeineCacheWithStats();
771773
}
772774

775+
@Test
776+
public void autoConfiguredCacheManagerCanBeSwapped() {
777+
load(CacheManagerPostProcessorConfiguration.class, "spring.cache.type=caffeine");
778+
validateCacheManager(SimpleCacheManager.class);
779+
CacheManagerPostProcessor postProcessor = this.context.getBean(
780+
CacheManagerPostProcessor.class);
781+
assertThat(postProcessor.cacheManagers).hasSize(1);
782+
assertThat(postProcessor.cacheManagers.get(0))
783+
.isInstanceOf(CaffeineCacheManager.class);
784+
}
785+
773786
private void validateCaffeineCacheWithStats() {
774787
CaffeineCacheManager cacheManager = validateCacheManager(
775788
CaffeineCacheManager.class);
@@ -1164,4 +1177,37 @@ public void customize(T cacheManager) {
11641177

11651178
}
11661179

1180+
@Configuration
1181+
@EnableCaching
1182+
static class CacheManagerPostProcessorConfiguration {
1183+
1184+
@Bean
1185+
public static BeanPostProcessor cacheManagerBeanPostProcessor() {
1186+
return new CacheManagerPostProcessor();
1187+
}
1188+
1189+
}
1190+
1191+
private static class CacheManagerPostProcessor implements BeanPostProcessor {
1192+
1193+
private final List<CacheManager> cacheManagers = new ArrayList<CacheManager>();
1194+
1195+
@Override
1196+
public Object postProcessBeforeInitialization(Object bean,
1197+
String beanName) throws BeansException {
1198+
return bean;
1199+
}
1200+
1201+
@Override
1202+
public Object postProcessAfterInitialization(Object bean,
1203+
String beanName) throws BeansException {
1204+
if (bean instanceof CacheManager) {
1205+
this.cacheManagers.add((CacheManager) bean);
1206+
return new SimpleCacheManager();
1207+
}
1208+
return bean;
1209+
}
1210+
1211+
}
1212+
11671213
}

0 commit comments

Comments
 (0)