1. 程式人生 > >@CacheEvict只能單一清除的擴充套件 -模糊-正則清除多條快取 解決

@CacheEvict只能單一清除的擴充套件 -模糊-正則清除多條快取 解決

[email protected](value="xx",key="xxx")只能單一刪除,但是

    @Cacheable(value = "autocms", key = "#root.targetClass+'.'+#root.method.name+'.'+#p0+'.'+#p1")
    public <T> PageInfo<T> getActivityByShowStatus(Map<String, Integer> paramMap, Class<T> cl) {

會根據不同的引數生成多條快取資料,之久導致的當出現數據更新的時候更新快取的困難

解決:

首先找到這一類的快取的共同點,同一類快取有著相同的字首,而java redis客戶端支援正則查詢和批量的刪除

1.問題一:在需要重新整理的快取的時候如何拿到這個字首,這個問題的取決於你的字首或者字尾是如何生成的

2.問題二:就是你如何的根據字首或者字尾去清除redis快取

實現方式

1.你可以寫個工具類,

2寫一個服務類注入到Spring中使用的時候直接拿出來

3.你可以使用Sring的Aop代理增強的方式進行處理

我是先使用的第二種,後來改成了第三種

下面直接上程式碼,程式碼裡面都有註釋

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 功能描述:需要清除的當前型別--當前類
 *
 * @author fuyuchao
 * DATE 2018/9/14.
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheRemove {

    /**
     * 需要清除的大類 例如 autocms 所有快取
     *
     * @return
     */
    String value() default "";


    /**
     * 需要清除的具體的額型別
     *
     * @return
     */
    String[] key() default {};
}
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Set;

/**
 * 功能描述:清除快取切面類
 *
 * @author fuyuchao
 * DATE 2018/9/14.
 */
@Component
@Aspect
public class CacheRemoveAspect {

    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource(name = "redisTemplate")
    RedisTemplate<String, String> redis;

    //截獲標有@CacheRemove的方法
    @Pointcut(value = "(execution(* *.*(..)) && @annotation(com.yooli.cms.cache.CacheRemove))")
    private void pointcut() {
    }

    /**
     * 功能描述: 切面在截獲方法返回值之後
     *
     * @return void
     * @throws
     * @author fuyuchao
     * @date 2018/9/14 16:55
     * @params [joinPoint]
     */
    @AfterReturning(value = "pointcut()")
    private void process(JoinPoint joinPoint) {
        //獲取被代理的類
        Object target = joinPoint.getTarget();
        //獲取切入方法的資料
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //獲取切入方法
        Method method = signature.getMethod();
        //獲得註解
        CacheRemove cacheRemove = method.getAnnotation(CacheRemove.class);

        if (cacheRemove != null) {
            //清除當前類的快取
            cleanRedisCache("*" + target.getClass().toString() + "*");

            String value = cacheRemove.value();
            if (!value.equals("")) {
                //快取的專案所有redis業務部快取
                cleanRedisCache("*" + value + "*");
            }
            //需要移除的正則key
            String[] keys = cacheRemove.key();
            for (String key : keys) {
                //指定清除的key的快取
                cleanRedisCache("*" + key + "*");
            }
        }
    }

    private void cleanRedisCache(String key) {
        if (key != null) {
            Set<String> stringSet = redis.keys(key);
            redis.delete(stringSet);//刪除快取
            logger.info("清除 " + key + " 快取");
        }
    }
}