使用切面註解編程實現redis模糊刪除數據之二使用spel表達式

傳送門:使用切面註解編程實現redis模糊刪除數據之一

之前雖然用切面編程實現了redis的模糊查詢,但是卻沒有實現像spring-redis原生的語法一樣的spEl表達式,比如#參數名這種形式,然後在網上找了一些資料,實現了和spring-redis一樣的spEl表達,可以使用#參數名或者#p0這樣的方式,下面是代碼

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Resource;

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.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import com.kq.highnet2.framework.base.common.annotation.CacheRemove;

@Aspect
@Component
public class CacheRemoveAspect {
    Logger logger=LoggerFactory.getLogger(this.getClass());
	@Resource(name = "redisTemplate") 
	RedisTemplate<String, String> redis;
	@Pointcut(value = "(execution(* *.*(..)) && "//截獲標有@CacheRemove的方法
			+ "@annotation(com.kq.highnet2.framework.base.common.annotation.CacheRemove))")
    private void pointcut() {}
	@AfterReturning(value = "pointcut()")//切面在方法返回值之後
	private void process(JoinPoint joinPoint){
	    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
	    Object[] args = joinPoint.getArgs();//切面方法的參數
	    Method method = signature.getMethod();//切面方法
	    CacheRemove cacheRemove = method.getAnnotation(CacheRemove.class);//獲得註解
	    if (cacheRemove != null){
	        String value = cacheRemove.value();//暫時沒用
	        String[] keys = cacheRemove.key(); //需要移除的正則key
	        for(String key:keys) {
	        	logger.info(key);
	        	key = parseKey(key, method, args);
	        	Set<String> keys2 = redis.keys(key);//獲得redis中符合正則的緩存
	        	redis.delete(keys2);//刪除緩存
	        	logger.info("刪除緩存:"+key);
	        }
	        
	    }
	}
    /** 
     *    獲取緩存的key  
     *    key 定義在註解上,支持SPEL表達式 
     * @param pjp 
     * @return 
     */  
    private String parseKey(String key,Method method,Object [] args){           
        //獲取被攔截方法參數名列表(使用Spring支持類庫)  
        LocalVariableTableParameterNameDiscoverer u =     
            new LocalVariableTableParameterNameDiscoverer();    
        String [] paraNameArr=u.getParameterNames(method);  
          
        //使用SPEL進行key的解析  
        ExpressionParser parser = new SpelExpressionParser();   
        //SPEL上下文  
        StandardEvaluationContext context = new StandardEvaluationContext();  
        //把方法參數放入SPEL上下文中  
        for(int i=0;i<paraNameArr.length;i++){  
            context.setVariable(paraNameArr[i], args[i]);  
        } 
        List<String> pList = descFormat(key);//獲取#p0這樣的表達式
        //將p0作爲參數放入SPEL上下文中
        for(String p:pList) {
        	context.setVariable(p.substring(1), args[Integer.valueOf(p.substring(2))]);
        }
        return parser.parseExpression(key).getValue(context,String.class);  
    } 
    /**
     * 提取出#p[數字]這樣的表達式
     * @param desc
     * @return
     */
    private static List<String> descFormat(String desc){  
        List<String> list = new ArrayList<>();  
        Pattern pattern = Pattern.compile("#p[0-9]+");   
        Matcher matcher = pattern.matcher(desc);   
        while(matcher.find()){   
            String t = matcher.group(0);   
            list.add(t);  
        }  
        return list;  
    }
}
這樣就可以和原來@Cacheable等註解上的用法一樣了
	@Caching(evict= {
		@CacheEvict(value="baseModulePermissionList",key="'baseModulePermissionList'+#userId"),
	})
	@CacheRemove(value="deletePermission",key = {"'baseButtonPermissionList'+#p0+'*'","'baseViewPermissionList'+#userId+'*'"})
	public void evictPermission(String userId) {
	}

親測可以使用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章