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;
}
}
可以關注來獲取對應的原始碼