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