springmvc redis @Cacheable扩展(一)
springmvc 中有自带的cache处理模块,可以是方法级别的缓存处理,那么在实际使用中,很可能自己造轮子,因为实际中永远会有更奇怪的需求点。比如:
1 清除缓存时候,能模糊的进行删除
2 针对不同的key,设置不同的过期时间
这2个是有些麻烦的需求,当然针对缓存内容,设置 key(这个 key 的确定)更让人难受,不好取舍,需要有一定的开发经验,否则只能不停的修改。
我们先集中处理第一个问题,模糊删除
- 1.查找方案
- 2.查看低版本redis实现
- 3.具体处理方式
明确问题,查找方案
可能网上有不少的解决方案
1. 首先我们从网上找到对应的修改的code,真的就是拿来就能用的那种,然后发现有2个function没有,然后就发现你是低版本,然后就没然后了。。
<properties>
<org.springframework-version>4.2.2.RELEASE</org.springframework-version>
<org.aspectj-version>1.8.2</org.aspectj-version>
<org.slf4j-version>1.7.21</org.slf4j-version>
<org.log4j2-version>2.8.2</org.log4j2-version>
</properties>
2. 根据第三个,可以看到,基于 redis template 的缓存处理,是有模糊处理的方法的,也就是说,可以做模糊处理。
3. 查看 spring 低版本 4.2.2 版本的 cache 的redis 类,进行简单的 仿做
。
查看低版本redis实现
因为使用springmvc时候,都会对 redis 进行配置,设置 ttl 等参数,那么,点进去看源码,就会发现
CustomizedRedisCacheManager
和 CustomizeRedisCache
,和 高版本的名字很像,那么仔细看看,发现 CustomizeRedisCache 就是需要改造的。
public void evict(RedisCacheElement element)
public void evict(Object key)
这2个函数。很可以,2个文件粘贴出来,直接做成注入,发现就直接可以在 @Cacheable 的时候断点看了。
这2个就是在删除缓存时候使用的。
改造一波
代码进行了删减,需要修改后的,可以联系我
CustomizedRedisCacheManager
/**
* CustomizedRedisCacheManager
*
* @desc 重新定义 oldcache 的 处理方式
*/
public class CustomizedRedisCacheManager extends RedisCacheManager {
protected RedisOperations getRedisOperations() {
return this.redisOperations;
}
protected RedisCachePrefix getCachePrefix() {
return this.cachePrefix;
}
protected boolean isUsePrefix() {
return this.usePrefix;
}
public void afterPropertiesSet() {
if (!CollectionUtils.isEmpty(this.configuredCacheNames)) {
Iterator var1 = this.configuredCacheNames.iterator();
while (var1.hasNext()) {
String cacheName = (String) var1.next();
this.createAndAddCache(cacheName);
}
this.configuredCacheNames.clear();
}
super.afterPropertiesSet();
}
protected Cache decorateCache(Cache cache) {
return this.isCacheAlreadyDecorated(cache) ? cache : super.decorateCache(cache);
}
protected boolean isCacheAlreadyDecorated(Cache cache) {
return this.isTransactionAware() && cache instanceof TransactionAwareCacheDecorator;
}
}
CustomizeRedisCache
/**
* RedisCacheResolver
*
* @desc springCache 的重载
*/
public class CustomizeRedisCache extends RedisCache {
private final RedisOperations redisOperations;
private final CustomizeRedisCache.RedisCacheMetadata cacheMetadata;
private final CacheValueAccessor cacheValueAccessor;
public CustomizeRedisCache(String name, byte[] prefix, RedisOperations<? extends Object, ? extends Object> redisOperations, long expiration) {
super(name, prefix, redisOperations, expiration);
Assert.hasText(name, "non-empty cache name is required");
this.cacheMetadata = new CustomizeRedisCache.RedisCacheMetadata(name, prefix);
this.cacheMetadata.setDefaultExpiration(expiration);
this.redisOperations = redisOperations;
this.cacheValueAccessor = new CustomizeRedisCache.CacheValueAccessor(redisOperations.getValueSerializer());
}
public <T> T get(Object key, Class<T> type) {
ValueWrapper wrapper = this.get(key);
return wrapper == null ? null : (T) wrapper.get();
}
public ValueWrapper get(Object key) {
return this.get((new RedisCacheKey(key)).usePrefix(this.cacheMetadata.getKeyPrefix()).withKeySerializer(this.redisOperations.getKeySerializer()));
}
/**
* 重点处理,进行重写
*
* @param key
*/
public void evict(Object key) {
if(key instanceof String){
String keyString=key.toString();
if(StringUtils.endsWith(keyString,"*")){
// evictLikePrefix(this.cacheMetadata.cacheName + keyString);
evictLikePrefix(keyString);
return;
}
if(StringUtils.startsWith(keyString,"*")){
// evictLikePrefix(this.cacheMetadata.cacheName + keyString);
evictLikePrefix(keyString);
return;
}
}
// 原始
RedisCacheElement redisCacheElement = new RedisCacheElement((new RedisCacheKey(key)).usePrefix(this.cacheMetadata.getKeyPrefix()).withKeySerializer(this.redisOperations.getKeySerializer()), (Object) null);
this.evict(redisCacheElement);
}
public void evict(RedisCacheElement element) {
Assert.notNull(element, "Element must not be null!");
this.redisOperations.execute(new CustomizeRedisCache.RedisCacheEvictCallback(new CustomizeRedisCache.BinaryRedisCacheElement(element, this.cacheValueAccessor), this.cacheMetadata));
}
/**
* 进行模糊处理 key
*
* @param key
*/
public void evictLikePrefix(Object key){
Set keys = this.redisOperations.keys(key);
if(keys != null && keys.size() > 0){
for(Object k : keys){
RedisCacheElement redisCacheElement = new RedisCacheElement((new RedisCacheKey(k)).usePrefix(this.cacheMetadata.getKeyPrefix()).withKeySerializer(this.redisOperations.getKeySerializer()), (Object) null);
this.evict(redisCacheElement);
}
}
}
public void clear() {
this.redisOperations.execute((RedisCallback) (this.cacheMetadata.usesKeyPrefix() ? new CustomizeRedisCache.RedisCacheCleanByPrefixCallback(this.cacheMetadata) : new CustomizeRedisCache.RedisCacheCleanByKeysCallback(this.cacheMetadata)));
}
public String getName() {
return this.cacheMetadata.getCacheName();
}
public Object getNativeCache() {
return this.redisOperations;
}
private ValueWrapper toWrapper(Object value) {
return value != null ? new SimpleValueWrapper(value) : null;
}
}
可以关注来获取对应的源码