001/*
002 * Copyright 2012-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.boot.autoconfigure.cache;
018
019import java.util.stream.Collectors;
020
021import org.springframework.beans.factory.InitializingBean;
022import org.springframework.beans.factory.ObjectProvider;
023import org.springframework.boot.autoconfigure.AutoConfigureAfter;
024import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
025import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration.CacheConfigurationImportSelector;
026import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
027import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
028import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
029import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration;
030import org.springframework.boot.autoconfigure.data.jpa.EntityManagerFactoryDependsOnPostProcessor;
031import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
032import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration;
033import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
034import org.springframework.boot.context.properties.EnableConfigurationProperties;
035import org.springframework.cache.CacheManager;
036import org.springframework.cache.annotation.EnableCaching;
037import org.springframework.cache.interceptor.CacheAspectSupport;
038import org.springframework.context.annotation.Bean;
039import org.springframework.context.annotation.Configuration;
040import org.springframework.context.annotation.Import;
041import org.springframework.context.annotation.ImportSelector;
042import org.springframework.core.type.AnnotationMetadata;
043import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
044import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
045import org.springframework.util.Assert;
046
047/**
048 * {@link EnableAutoConfiguration Auto-configuration} for the cache abstraction. Creates a
049 * {@link CacheManager} if necessary when caching is enabled via {@link EnableCaching}.
050 * <p>
051 * Cache store can be auto-detected or specified explicitly via configuration.
052 *
053 * @author Stephane Nicoll
054 * @since 1.3.0
055 * @see EnableCaching
056 */
057@Configuration
058@ConditionalOnClass(CacheManager.class)
059@ConditionalOnBean(CacheAspectSupport.class)
060@ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
061@EnableConfigurationProperties(CacheProperties.class)
062@AutoConfigureAfter({ CouchbaseAutoConfiguration.class, HazelcastAutoConfiguration.class,
063                HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class })
064@Import(CacheConfigurationImportSelector.class)
065public class CacheAutoConfiguration {
066
067        @Bean
068        @ConditionalOnMissingBean
069        public CacheManagerCustomizers cacheManagerCustomizers(
070                        ObjectProvider<CacheManagerCustomizer<?>> customizers) {
071                return new CacheManagerCustomizers(
072                                customizers.orderedStream().collect(Collectors.toList()));
073        }
074
075        @Bean
076        public CacheManagerValidator cacheAutoConfigurationValidator(
077                        CacheProperties cacheProperties, ObjectProvider<CacheManager> cacheManager) {
078                return new CacheManagerValidator(cacheProperties, cacheManager);
079        }
080
081        @Configuration
082        @ConditionalOnClass(LocalContainerEntityManagerFactoryBean.class)
083        @ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
084        protected static class CacheManagerJpaDependencyConfiguration
085                        extends EntityManagerFactoryDependsOnPostProcessor {
086
087                public CacheManagerJpaDependencyConfiguration() {
088                        super("cacheManager");
089                }
090
091        }
092
093        /**
094         * Bean used to validate that a CacheManager exists and provide a more meaningful
095         * exception.
096         */
097        static class CacheManagerValidator implements InitializingBean {
098
099                private final CacheProperties cacheProperties;
100
101                private final ObjectProvider<CacheManager> cacheManager;
102
103                CacheManagerValidator(CacheProperties cacheProperties,
104                                ObjectProvider<CacheManager> cacheManager) {
105                        this.cacheProperties = cacheProperties;
106                        this.cacheManager = cacheManager;
107                }
108
109                @Override
110                public void afterPropertiesSet() {
111                        Assert.notNull(this.cacheManager.getIfAvailable(),
112                                        () -> "No cache manager could "
113                                                        + "be auto-configured, check your configuration (caching "
114                                                        + "type is '" + this.cacheProperties.getType() + "')");
115                }
116
117        }
118
119        /**
120         * {@link ImportSelector} to add {@link CacheType} configuration classes.
121         */
122        static class CacheConfigurationImportSelector implements ImportSelector {
123
124                @Override
125                public String[] selectImports(AnnotationMetadata importingClassMetadata) {
126                        CacheType[] types = CacheType.values();
127                        String[] imports = new String[types.length];
128                        for (int i = 0; i < types.length; i++) {
129                                imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
130                        }
131                        return imports;
132                }
133
134        }
135
136}