mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
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
This commit is contained in:
parent
7392c57343
commit
1314aaa368
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2016 the original author or authors.
|
* Copyright 2012-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -18,14 +18,8 @@ package org.springframework.boot.autoconfigure.cache;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
|
||||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
@ -46,7 +40,6 @@ import org.springframework.context.annotation.Bean;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.context.annotation.ImportSelector;
|
import org.springframework.context.annotation.ImportSelector;
|
||||||
import org.springframework.context.annotation.Role;
|
|
||||||
import org.springframework.core.type.AnnotationMetadata;
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
|
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
|
||||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||||
@ -73,8 +66,6 @@ import org.springframework.util.Assert;
|
|||||||
@Import(CacheConfigurationImportSelector.class)
|
@Import(CacheConfigurationImportSelector.class)
|
||||||
public class CacheAutoConfiguration {
|
public class CacheAutoConfiguration {
|
||||||
|
|
||||||
static final String VALIDATOR_BEAN_NAME = "cacheAutoConfigurationValidator";
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
public CacheManagerCustomizers cacheManagerCustomizers(
|
public CacheManagerCustomizers cacheManagerCustomizers(
|
||||||
@ -83,14 +74,10 @@ public class CacheAutoConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
public CacheManagerValidator cacheAutoConfigurationValidator(
|
||||||
public static CacheManagerValidatorPostProcessor cacheAutoConfigurationValidatorPostProcessor() {
|
CacheProperties cacheProperties,
|
||||||
return new CacheManagerValidatorPostProcessor();
|
ObjectProvider<CacheManager> cacheManager) {
|
||||||
}
|
return new CacheManagerValidator(cacheProperties, cacheManager);
|
||||||
|
|
||||||
@Bean(name = VALIDATOR_BEAN_NAME)
|
|
||||||
public CacheManagerValidator cacheAutoConfigurationValidator() {
|
|
||||||
return new CacheManagerValidator();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ -105,50 +92,25 @@ public class CacheAutoConfiguration {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link BeanFactoryPostProcessor} to ensure that the {@link CacheManagerValidator}
|
|
||||||
* is triggered before {@link CacheAspectSupport} but without causing early
|
|
||||||
* instantiation.
|
|
||||||
*/
|
|
||||||
static class CacheManagerValidatorPostProcessor implements BeanFactoryPostProcessor {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
|
|
||||||
throws BeansException {
|
|
||||||
for (String name : beanFactory.getBeanNamesForType(CacheAspectSupport.class,
|
|
||||||
false, false)) {
|
|
||||||
BeanDefinition definition = beanFactory.getBeanDefinition(name);
|
|
||||||
definition.setDependsOn(
|
|
||||||
append(definition.getDependsOn(), VALIDATOR_BEAN_NAME));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String[] append(String[] array, String value) {
|
|
||||||
String[] result = new String[array != null ? array.length + 1 : 1];
|
|
||||||
if (array != null) {
|
|
||||||
System.arraycopy(array, 0, result, 0, array.length);
|
|
||||||
}
|
|
||||||
result[result.length - 1] = value;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bean used to validate that a CacheManager exists and provide a more meaningful
|
* Bean used to validate that a CacheManager exists and provide a more meaningful
|
||||||
* exception.
|
* exception.
|
||||||
*/
|
*/
|
||||||
static class CacheManagerValidator {
|
static class CacheManagerValidator implements InitializingBean {
|
||||||
|
|
||||||
@Autowired
|
private final CacheProperties cacheProperties;
|
||||||
private CacheProperties cacheProperties;
|
|
||||||
|
|
||||||
@Autowired(required = false)
|
private final ObjectProvider<CacheManager> cacheManager;
|
||||||
private CacheManager cacheManager;
|
|
||||||
|
|
||||||
@PostConstruct
|
CacheManagerValidator(CacheProperties cacheProperties,
|
||||||
public void checkHasCacheManager() {
|
ObjectProvider<CacheManager> cacheManager) {
|
||||||
Assert.notNull(this.cacheManager,
|
this.cacheProperties = cacheProperties;
|
||||||
|
this.cacheManager = cacheManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() {
|
||||||
|
Assert.notNull(this.cacheManager.getIfAvailable(),
|
||||||
"No cache manager could "
|
"No cache manager could "
|
||||||
+ "be auto-configured, check your configuration (caching "
|
+ "be auto-configured, check your configuration (caching "
|
||||||
+ "type is '" + this.cacheProperties.getType() + "')");
|
+ "type is '" + this.cacheProperties.getType() + "')");
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2017 the original author or authors.
|
* Copyright 2012-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -51,9 +51,11 @@ import org.junit.Rule;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.ExpectedException;
|
import org.junit.rules.ExpectedException;
|
||||||
|
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.DirectFieldAccessor;
|
import org.springframework.beans.DirectFieldAccessor;
|
||||||
import org.springframework.beans.factory.BeanCreationException;
|
import org.springframework.beans.factory.BeanCreationException;
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
import org.springframework.boot.autoconfigure.cache.support.MockCachingProvider;
|
import org.springframework.boot.autoconfigure.cache.support.MockCachingProvider;
|
||||||
import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration;
|
import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration;
|
||||||
import org.springframework.boot.test.util.EnvironmentTestUtils;
|
import org.springframework.boot.test.util.EnvironmentTestUtils;
|
||||||
@ -770,6 +772,17 @@ public class CacheAutoConfigurationTests {
|
|||||||
validateCaffeineCacheWithStats();
|
validateCaffeineCacheWithStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void autoConfiguredCacheManagerCanBeSwapped() {
|
||||||
|
load(CacheManagerPostProcessorConfiguration.class, "spring.cache.type=caffeine");
|
||||||
|
validateCacheManager(SimpleCacheManager.class);
|
||||||
|
CacheManagerPostProcessor postProcessor = this.context.getBean(
|
||||||
|
CacheManagerPostProcessor.class);
|
||||||
|
assertThat(postProcessor.cacheManagers).hasSize(1);
|
||||||
|
assertThat(postProcessor.cacheManagers.get(0))
|
||||||
|
.isInstanceOf(CaffeineCacheManager.class);
|
||||||
|
}
|
||||||
|
|
||||||
private void validateCaffeineCacheWithStats() {
|
private void validateCaffeineCacheWithStats() {
|
||||||
CaffeineCacheManager cacheManager = validateCacheManager(
|
CaffeineCacheManager cacheManager = validateCacheManager(
|
||||||
CaffeineCacheManager.class);
|
CaffeineCacheManager.class);
|
||||||
@ -1164,4 +1177,37 @@ public class CacheAutoConfigurationTests {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableCaching
|
||||||
|
static class CacheManagerPostProcessorConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public static BeanPostProcessor cacheManagerBeanPostProcessor() {
|
||||||
|
return new CacheManagerPostProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CacheManagerPostProcessor implements BeanPostProcessor {
|
||||||
|
|
||||||
|
private final List<CacheManager> cacheManagers = new ArrayList<CacheManager>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object postProcessBeforeInitialization(Object bean,
|
||||||
|
String beanName) throws BeansException {
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object postProcessAfterInitialization(Object bean,
|
||||||
|
String beanName) throws BeansException {
|
||||||
|
if (bean instanceof CacheManager) {
|
||||||
|
this.cacheManagers.add((CacheManager) bean);
|
||||||
|
return new SimpleCacheManager();
|
||||||
|
}
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user