001/* 002 * Copyright 2002-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 * https://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.cache.jcache.interceptor; 018 019import java.util.Collection; 020import java.util.function.Supplier; 021 022import org.springframework.beans.BeanUtils; 023import org.springframework.beans.factory.BeanFactory; 024import org.springframework.beans.factory.BeanFactoryAware; 025import org.springframework.beans.factory.NoSuchBeanDefinitionException; 026import org.springframework.beans.factory.NoUniqueBeanDefinitionException; 027import org.springframework.beans.factory.SmartInitializingSingleton; 028import org.springframework.cache.Cache; 029import org.springframework.cache.CacheManager; 030import org.springframework.cache.interceptor.CacheOperationInvocationContext; 031import org.springframework.cache.interceptor.CacheResolver; 032import org.springframework.cache.interceptor.KeyGenerator; 033import org.springframework.cache.interceptor.SimpleCacheResolver; 034import org.springframework.cache.interceptor.SimpleKeyGenerator; 035import org.springframework.lang.Nullable; 036import org.springframework.util.Assert; 037import org.springframework.util.function.SingletonSupplier; 038import org.springframework.util.function.SupplierUtils; 039 040/** 041 * The default {@link JCacheOperationSource} implementation delegating 042 * default operations to configurable services with sensible defaults 043 * when not present. 044 * 045 * @author Stephane Nicoll 046 * @author Juergen Hoeller 047 * @since 4.1 048 */ 049public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSource 050 implements BeanFactoryAware, SmartInitializingSingleton { 051 052 @Nullable 053 private SingletonSupplier<CacheManager> cacheManager; 054 055 @Nullable 056 private SingletonSupplier<CacheResolver> cacheResolver; 057 058 @Nullable 059 private SingletonSupplier<CacheResolver> exceptionCacheResolver; 060 061 private SingletonSupplier<KeyGenerator> keyGenerator; 062 063 private final SingletonSupplier<KeyGenerator> adaptedKeyGenerator = 064 SingletonSupplier.of(() -> new KeyGeneratorAdapter(this, getKeyGenerator())); 065 066 @Nullable 067 private BeanFactory beanFactory; 068 069 070 /** 071 * Construct a new {@code DefaultJCacheOperationSource} with the default key generator. 072 * @see SimpleKeyGenerator 073 */ 074 public DefaultJCacheOperationSource() { 075 this.keyGenerator = SingletonSupplier.of(SimpleKeyGenerator::new); 076 } 077 078 /** 079 * Construct a new {@code DefaultJCacheOperationSource} with the given cache manager, 080 * cache resolver and key generator suppliers, applying the corresponding default 081 * if a supplier is not resolvable. 082 * @since 5.1 083 */ 084 public DefaultJCacheOperationSource( 085 @Nullable Supplier<CacheManager> cacheManager, @Nullable Supplier<CacheResolver> cacheResolver, 086 @Nullable Supplier<CacheResolver> exceptionCacheResolver, @Nullable Supplier<KeyGenerator> keyGenerator) { 087 088 this.cacheManager = SingletonSupplier.ofNullable(cacheManager); 089 this.cacheResolver = SingletonSupplier.ofNullable(cacheResolver); 090 this.exceptionCacheResolver = SingletonSupplier.ofNullable(exceptionCacheResolver); 091 this.keyGenerator = new SingletonSupplier<>(keyGenerator, SimpleKeyGenerator::new); 092 } 093 094 095 /** 096 * Set the default {@link CacheManager} to use to lookup cache by name. 097 * Only mandatory if the {@linkplain CacheResolver cache resolver} has not been set. 098 */ 099 public void setCacheManager(@Nullable CacheManager cacheManager) { 100 this.cacheManager = SingletonSupplier.ofNullable(cacheManager); 101 } 102 103 /** 104 * Return the specified cache manager to use, if any. 105 */ 106 @Nullable 107 public CacheManager getCacheManager() { 108 return SupplierUtils.resolve(this.cacheManager); 109 } 110 111 /** 112 * Set the {@link CacheResolver} to resolve regular caches. If none is set, a default 113 * implementation using the specified cache manager will be used. 114 */ 115 public void setCacheResolver(@Nullable CacheResolver cacheResolver) { 116 this.cacheResolver = SingletonSupplier.ofNullable(cacheResolver); 117 } 118 119 /** 120 * Return the specified cache resolver to use, if any. 121 */ 122 @Nullable 123 public CacheResolver getCacheResolver() { 124 return SupplierUtils.resolve(this.cacheResolver); 125 } 126 127 /** 128 * Set the {@link CacheResolver} to resolve exception caches. If none is set, a default 129 * implementation using the specified cache manager will be used. 130 */ 131 public void setExceptionCacheResolver(@Nullable CacheResolver exceptionCacheResolver) { 132 this.exceptionCacheResolver = SingletonSupplier.ofNullable(exceptionCacheResolver); 133 } 134 135 /** 136 * Return the specified exception cache resolver to use, if any. 137 */ 138 @Nullable 139 public CacheResolver getExceptionCacheResolver() { 140 return SupplierUtils.resolve(this.exceptionCacheResolver); 141 } 142 143 /** 144 * Set the default {@link KeyGenerator}. If none is set, a {@link SimpleKeyGenerator} 145 * honoring the JSR-107 {@link javax.cache.annotation.CacheKey} and 146 * {@link javax.cache.annotation.CacheValue} will be used. 147 */ 148 public void setKeyGenerator(KeyGenerator keyGenerator) { 149 this.keyGenerator = SingletonSupplier.of(keyGenerator); 150 } 151 152 /** 153 * Return the specified key generator to use. 154 */ 155 public KeyGenerator getKeyGenerator() { 156 return this.keyGenerator.obtain(); 157 } 158 159 @Override 160 public void setBeanFactory(BeanFactory beanFactory) { 161 this.beanFactory = beanFactory; 162 } 163 164 165 @Override 166 public void afterSingletonsInstantiated() { 167 // Make sure that the cache resolver is initialized. An exception cache resolver is only 168 // required if the exceptionCacheName attribute is set on an operation. 169 Assert.notNull(getDefaultCacheResolver(), "Cache resolver should have been initialized"); 170 } 171 172 173 @Override 174 protected <T> T getBean(Class<T> type) { 175 Assert.state(this.beanFactory != null, () -> "BeanFactory required for resolution of [" + type + "]"); 176 try { 177 return this.beanFactory.getBean(type); 178 } 179 catch (NoUniqueBeanDefinitionException ex) { 180 throw new IllegalStateException("No unique [" + type.getName() + "] bean found in application context - " + 181 "mark one as primary, or declare a more specific implementation type for your cache", ex); 182 } 183 catch (NoSuchBeanDefinitionException ex) { 184 if (logger.isDebugEnabled()) { 185 logger.debug("No bean of type [" + type.getName() + "] found in application context", ex); 186 } 187 return BeanUtils.instantiateClass(type); 188 } 189 } 190 191 protected CacheManager getDefaultCacheManager() { 192 if (getCacheManager() == null) { 193 Assert.state(this.beanFactory != null, "BeanFactory required for default CacheManager resolution"); 194 try { 195 this.cacheManager = SingletonSupplier.of(this.beanFactory.getBean(CacheManager.class)); 196 } 197 catch (NoUniqueBeanDefinitionException ex) { 198 throw new IllegalStateException("No unique bean of type CacheManager found. "+ 199 "Mark one as primary or declare a specific CacheManager to use."); 200 } 201 catch (NoSuchBeanDefinitionException ex) { 202 throw new IllegalStateException("No bean of type CacheManager found. Register a CacheManager "+ 203 "bean or remove the @EnableCaching annotation from your configuration."); 204 } 205 } 206 return getCacheManager(); 207 } 208 209 @Override 210 protected CacheResolver getDefaultCacheResolver() { 211 if (getCacheResolver() == null) { 212 this.cacheResolver = SingletonSupplier.of(new SimpleCacheResolver(getDefaultCacheManager())); 213 } 214 return getCacheResolver(); 215 } 216 217 @Override 218 protected CacheResolver getDefaultExceptionCacheResolver() { 219 if (getExceptionCacheResolver() == null) { 220 this.exceptionCacheResolver = SingletonSupplier.of(new LazyCacheResolver()); 221 } 222 return getExceptionCacheResolver(); 223 } 224 225 @Override 226 protected KeyGenerator getDefaultKeyGenerator() { 227 return this.adaptedKeyGenerator.obtain(); 228 } 229 230 231 /** 232 * Only resolve the default exception cache resolver when an exception needs to be handled. 233 * <p>A non-JSR-107 setup requires either a {@link CacheManager} or a {@link CacheResolver}. 234 * If only the latter is specified, it is not possible to extract a default exception 235 * {@code CacheResolver} from a custom {@code CacheResolver} implementation so we have to 236 * fall back on the {@code CacheManager}. 237 * <p>This gives this weird situation of a perfectly valid configuration that breaks all 238 * the sudden because the JCache support is enabled. To avoid this we resolve the default 239 * exception {@code CacheResolver} as late as possible to avoid such hard requirement 240 * in other cases. 241 */ 242 class LazyCacheResolver implements CacheResolver { 243 244 private final SingletonSupplier<CacheResolver> cacheResolver = 245 SingletonSupplier.of(() -> new SimpleExceptionCacheResolver(getDefaultCacheManager())); 246 247 @Override 248 public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) { 249 return this.cacheResolver.obtain().resolveCaches(context); 250 } 251 } 252 253}