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

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

举例,自定义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 "";

}

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)
全栈程序员-站长的头像全栈程序员-站长

相关推荐

  • 彻底解决Intellij IDEA中文乱码问题(亲测成功)「建议收藏」

    关于JAVA IDE开发工具,Eclipse系列和Intelli IDEA是大部分公司的主要选择,从开发者的选择角度,Intellij IDEA似乎比Eclipse系列更受欢迎一些。当我们使用Intellij IDEA开发时,我们发现出现中文乱码问题,造成中…

    2022年3月13日
  • Simulink学习笔记(三)——Simulink自动代码生成(二)「建议收藏」

    前言:   上一篇文章详细学习了如何通过Simulink建立系统模型,进而生成嵌入式代码。本文通过实例进一步加深对代码自动生成的理解和应用。一、建立系统框图      为了方便起见,在这里我们实现一个的简单算法,我们在simulink中建立系统框图如下所示:  在生成代码之前,给k输入一个数,在命令行输入k=3,如下所示:然后配置一些参数,ctrl+E调出Configuration …

    2022年4月10日
  • vue双向绑定失效_vue热更新失效

    vue双向绑定失效_vue热更新失效为什么会失效呢首先vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的实现方式是get和set方法然后是通过Object.defineProperty()来实现数据劫持的。然后呢要是,实现数据的双向绑定,首先要对数据进行劫持监听,因为写的代码没有被监听到,所以只能手动setthis.$set(obj,key,value)查找的资料:1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。2.实现一个订阅者Watche..

    2022年9月14日
  • java输入的方法_java输入一个数

    java输入的方法_java输入一个数java输入语句的方法:1、输入单个字符【charc=(char)System.in.read()】;2、输入整数或者字符串【inta=cin.nextInt()】;3、可以用BufferedReader类输入。java输入语句的方法:如果你要进行输入,请一定加上两个包importjava.util.*;importjava.io.*;请看下面例子用于输入单个字符importjava.i…

    2022年9月21日
  • 数仓建模—数据安全「建议收藏」

    数仓建模—数据安全「建议收藏」数据安全差分隐私差分隐私是用来防范差分攻击的,差分隐私(英语:differentialprivacy)是密码学中的一种手段,旨在提供一种当从统计数据库查询时,最大化数据查询的准确性,同时最大限度减少识别其记录的机会比如有一群人出去聚餐,那么其中某人是否是单身狗就属于差分隐私。为了更形式化地描述差分隐私,我们需要先定义相邻数据集。现给定两个数据集D和D’,若它们有且仅有一条数据不一样,那我们就称此二者为相邻数据集。那么对于一个随机化算法(所谓随机化算法,是指对特定输入,该算法的输出不是固定值,而是服

    2022年5月21日
  • 华为交换机配置不同vlan不同网段互通[通俗易懂]

    华为交换机配置不同vlan不同网段互通[通俗易懂]在一台交换机中实现不同vlan不同网段相互通信Pc1:Pc2:Sw1:<Huawei>system-view1、创建vlan[Huawei]vlan2[Huawei-vlan2]quit[Huawei]vlan3[Huawei-vlan3]quit2、进入接口配置[Huawei]interfaceGigabitEthernet0/0/1[Huaw…

    2022年9月4日

发表回复

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

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