经过前连篇整合介绍,基本可以满足大多数使用场景了,作为矫情的码农来讲,除了灵活可控的缓存时间,还想简化
缓存名称设置,干脆完全不设置,在通用层统一处理缓存空间和key的生成。
### 期望使用方式如下
@Cacheable 无需设置value 和key
```
@Cacheable
@CacheExpire(value = 2 * DateUtils.ONE_DAY_SECONDS)
public ThirdUser query(@KeyParam String openId) {
return db.from(ThirdUser.class).where("open_id", openId).first(ThirdUser.class);
}
```
### 如果Cacheable 不设置value 会怎样呢
```
java.lang.IllegalStateException: No cache could be resolved for 'Builder[public cn.cube.gopher.entity.ThirdUser cn.cube.gopher.dao.impl.ThirdUserDao.query(java.lang.String)] caches=[] | key='' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'' using resolver 'org.springframework.cache.interceptor.SimpleCacheResolver@63cf578f'. At least one cache should be provided per cache operation.
at org.springframework.cache.interceptor.CacheAspectSupport.getCaches(CacheAspectSupport.java:255)
at org.springframework.cache.interceptor.CacheAspectSupport$CacheOperationContext.<init>(CacheAspectSupport.java:707)
at org.springframework.cache.interceptor.CacheAspectSupport.getOperationContext(CacheAspectSupport.java:265)
at org.springframework.cache.interceptor.CacheAspectSupport$CacheOperationContexts.<init>(CacheAspectSupport.java:598)
```
### 添加CacheResolver
通过CacheAspectSupport 我们知道,如果不设置Cacheable value属性,就会报错。那么我们看一下他的实现逻辑。
```
protected Collection<? extends Cache> getCaches(
CacheOperationInvocationContext<CacheOperation> context, CacheResolver cacheResolver) {
Collection<? extends Cache> caches = cacheResolver.resolveCaches(context);
//cacheResolver 获取caches为空,所以抛出IllegalStateException异常
if (caches.isEmpty()) {
throw new IllegalStateException("No cache could be resolved for '" +
context.getOperation() + "' using resolver '" + cacheResolver +
"'. At least one cache should be provided per cache operation.");
}
return caches;
}
```
现在我们知道是因为CacheResolver.resolveCaches为空导致抛出异常,事实上我们根本就没设置缓存空间,当然就不会存在对一个的cache。这也正是我们要处理的,处理办法就是用当前类全路径作为该cache的name。现在我们还有一个问题,就是CacheResolver是从哪里设置的呢。就在CachingConfigurerSupport 中。CachingConfigurerSupport 为缓存暴露了一些自定义接口,其中就有一个cacheResolver函数返回值CacheResolver,下面我们来自定义个CacheResolver。
```
public class CustomerCacheResolver extends SimpleCacheResolver {
public CubeCacheResolver(){
super();
}
public CubeCacheResolver(CacheManager cacheManager) {
super(cacheManager);
}
@Override
protected Collection<String> getCacheNames(CacheOperationInvocationContext<?> context) {
Set<String> cacheNames = context.getOperation().getCacheNames();
#当发现没有设置cacheName时,把目标类的全路径名设置为缓存空间名
if (CollectionUtils.isEmpty(cacheNames)){
String cacheName = context.getTarget().getClass().getName();
cacheNames.add(cacheName);
}
return cacheNames;
}
}
```
重写CachingConfigurerSupport cacheResolver函数
```
@Configuration
@EnableCaching
public class RedisConfig extends CacheConfig {
private CacheManager cacheManager;
@Autowired
public void setCacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration defaultCacheConfig = getRedisCacheConfiguration();
cacheManager = new CustomerCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(factory),defaultCacheConfig);
}
@Override
public CacheResolver cacheResolver() {
return new CustomerCacheResolver(cacheManager);
}
}
```
转载保留出处[http://www.threeperson.com/users/zld406504302/articles/2145)