Springboot自定义注解,支持SPEL表达式

Springboot自定义注解,支持SPEL表达式举例,自定义redis模糊删除注解1.自定义注解importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;@Target(E…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

举例,自定义redis模糊删除注解

1.自定义注解

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

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheEvictFuzzy {
    /**
     * redis key集合,模糊删除
     * @return
     */
    String[] key() default "";

}

Jetbrains全家桶1年46,售后保障稳定

2.使用AOP拦截方法,解析注解参数

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
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.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.annotation.Order;
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 java.lang.reflect.Method;
import java.util.Set;
@Aspect
@Order(1)
@Component
public class CacheCleanFuzzyAspect {
    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private RedisUtil redis;

    //指定要执行AOP的方法
    @Pointcut(value = "@annotation(cacheEvictFuzzy)")
    public void pointCut(CacheEvictFuzzy cacheEvictFuzzy){}


    // 设置切面为加有 @RedisCacheable注解的方法
    @Around("@annotation(cacheEvictFuzzy)")
    public Object around(ProceedingJoinPoint proceedingJoinPoint, CacheEvictFuzzy cacheEvictFuzzy){
        return doRedis(proceedingJoinPoint, cacheEvictFuzzy);
    }
    @AfterThrowing(pointcut = "@annotation(cacheEvictFuzzy)", throwing = "error")
    public void afterThrowing (Throwable  error, CacheEvictFuzzy cacheEvictFuzzy){
        logger.error(error.getMessage());
    }

    /**
     * 删除缓存
     * @param proceedingJoinPoint
     * @param cacheEvictFuzzy
     * @return
     */
    private Object doRedis (ProceedingJoinPoint proceedingJoinPoint, CacheEvictFuzzy cacheEvictFuzzy){
        Object result = null;
        //得到被切面修饰的方法的参数列表
        Object[] args = proceedingJoinPoint.getArgs();
        // 得到被代理的方法
        Method method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();
        String[] keys = cacheEvictFuzzy.key();
        Set<String> keySet = null;
        String realkey = "";
        for (int i = 0; i < keys.length; i++) {
            if (StringUtils.isBlank(keys[i])){
                continue;
            }
            realkey = parseKey(keys[i], method, args);
            keySet = redis.keys("*"+realkey+"*");
            if (null != keySet && keySet.size()>0){
                redis.delKeys(keySet);
                logger.debug("拦截到方法:" + proceedingJoinPoint.getSignature().getName() + "方法");
                logger.debug("删除的数据key为:"+keySet.toString());
            }
        }
        try {
            result = proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }finally {
            return result;
        }
    }
    /**
     * 获取缓存的key
     * key 定义在注解上,支持SPEL表达式
     * @return
     */
    private String parseKey(String key, Method method, Object [] args){

        if(StringUtils.isEmpty(key)) return null;

        //获取被拦截方法参数名列表(使用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]);
        }
        return parser.parseExpression(key).getValue(context,String.class);
    }
}

完事啦!

大家可以注意到关键方法就是parseKey

    /**
     * 获取缓存的key
     * key 定义在注解上,支持SPEL表达式
     * @return
     */
    private String parseKey(String key, Method method, Object [] args){

        if(StringUtils.isEmpty(key)) return null;

        //获取被拦截方法参数名列表(使用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]);
        }
        return parser.parseExpression(key).getValue(context,String.class);
    }

ok啦,大家记得点赞加关注啊!

双击评论666走起!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/230826.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • mybatis 分页查询 limit

    mybatis 分页查询 limit解决方案:#{pagenumber}—–>${pagenumber}

    2022年5月16日
    35
  • Java的Scanner输入时,next()和nextLine()的区别[通俗易懂]

    Java的Scanner输入时,next()和nextLine()的区别[通俗易懂]nextLine()不要和其他next方法一起用!!!尤其nextLine()不要放在它们后面!!!这个问题已经坑了我好多次了,但是每次都没有在意,主要是没反应过来出现问题的原因。今天阿里内推测验,又被nextLine()狠狠坑了一下。逻辑思路都是对的,就输入的数据不对。因为限时半小时,所以时间比较紧张,最后还是没弄出来。后来百度查了两者区别,果然问题是出在这里,改完之后问题就解决了。可怜我的…

    2022年6月10日
    40
  • 可用的NTP服务器地址「建议收藏」

    可用的NTP服务器地址「建议收藏」国内可用的Internet时间同步服务器地址(NTP时间服务器)好在阿里云提供了7个NTP时间服务器也就是Internet时间同步服务器地址ntp1.aliyun.comntp2.aliyun.comntp3.aliyun.comntp4.aliyun.comntp5.aliyun.comntp6.aliyun.comntp7.aliyun.com以下红色部分是我能ping通的地址,不能平通的也…

    2022年6月14日
    29
  • Python 求圆的面积[通俗易懂]

    Python 求圆的面积[通俗易懂]r=int(input(‘输入半径值:’))area=3.1415*r*rprint(area)#保留小数点后两位print(‘{:.2f}’.format(area))“`

    2022年10月22日
    0
  • 处理:/var/redis/run/redis_6379.pid exists, process is already running or crashed「建议收藏」

    处理:/var/redis/run/redis_6379.pid exists, process is already running or crashed「建议收藏」命令;serviceredisstart/var/redis/run/redis_6379.pidexists,processisalreadyrunningorcrashed引起这类问题一般都是强制关掉电源或断电造成的,也是没等linux正常关机科学的处理办法2种1:可用安装文件启动redis-server/etc/re

    2022年6月7日
    33
  • javascript 中contentWindow和 frames

    javascript 中contentWindow和 framescontentWindow属性是指指定的frame或者iframe所在的window对象IE 中为frames["id"]其他为document.getElementById("id").contentWindowcontentWindow属性是指指定的frame或者iframe所在的window对象在IE中iframe或者frame的contentWindow属性可以省略,但在Firef…

    2022年10月21日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号