iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >如何使用Springboot自定义注解并支持SPEL表达式
  • 760
分享到

如何使用Springboot自定义注解并支持SPEL表达式

2023-06-29 05:06:30 760人浏览 独家记忆
摘要

这篇文章主要介绍了如何使用SpringBoot自定义注解并支持SPEL表达式,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。springboot自定义注解,支持SPEL表达式举

这篇文章主要介绍了如何使用SpringBoot自定义注解并支持SPEL表达式,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

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

举例,自定义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 {        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)@Componentpublic 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());    }         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;        }    }        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

        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);    }

自定义注解结合切面和spel表达式

在我们的实际开发中可能存在这么一种情况,当方法参数中的某些条件成立的时候,需要执行一些逻辑处理,比如输出日志。而这些代码可能都是差不多的,那么这个时候就可以结合自定义注解加上切面加上spel表达式进行处理。就比如在spring中我们可以使用@Cacheable(key="#xx")实现缓存,这个#xx就是一个spel表达式。

需求:我们需要将service层方法中方法的某个参数的值大于0.5的方法,输出方法执行日志。(需要了解一些spel表达式的语法)

实现步骤:

自定义一个注解Log

自定义一个切面,拦截所有方法上存在@Log注解修饰的方法

写一个service层方法,方法上标注@Log注解

难点:

在切面中需要拿到具体执行方法的方法名,可以使用spring提供的LocalVariableTableParameterNameDiscoverer来获取到

自定义一个注解

注意:注解中的spel的值是必须的,且spel表达式返回的结果应该是一个布尔值

@Target({ ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)public @interface Log {String spel();String desc() default "描述";}

自定义一个service类,在需要拦截的方法上加上@Log注解

如何使用Springboot自定义注解并支持SPEL表达式

写一个自定义切面

注意一下解析spel表达式中context的设值即可

@Component@Aspectpublic class LogAspect {ExpressionParser parser = new SpelExpressionParser();LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();@Around("@annotation(log)")public Object invoked(ProceedingJoinPoint pjp, Log log) throws Throwable {Object[] args = pjp.getArgs();Method method = ((MethodSignature) pjp.getSignature()).getMethod();String spel = log.spel();String[] params = discoverer.getParameterNames(method);EvaluationContext context = new StandardEvaluationContext();for (int len = 0; len < params.length; len++) {context.setVariable(params[len], args[len]);}Expression expression = parser.parseExpression(spel);if (expression.getValue(context, Boolean.class)) {System.out.println(log.desc() + ",在" + new SimpleDateFORMat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "执行方法," + pjp.getTarget().getClass() + "." + method.getName()                         + "(" + convertArgs(args) + ")");}return pjp.proceed();}private String convertArgs(Object[] args) {StringBuilder builder = new StringBuilder();for (Object arg : args) {if (null == arg) {builder.append("null");} else {builder.append(arg.toString());}builder.append(',');}builder.setCharAt(builder.length() - 1, ' ');return builder.toString();}}

pom文件的依赖

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.2.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-Maven-plugin</artifactId></plugin></plugins></build>

测试

如何使用Springboot自定义注解并支持SPEL表达式

增加内容

当我们想在自己写的spel表达式中调用spring bean 管理的方法时,如何写。spel表达式支持使用 @来引用bean,但是此时需要注入BeanFactory

如何使用Springboot自定义注解并支持SPEL表达式

感谢你能够认真阅读完这篇文章,希望小编分享的“如何使用Springboot自定义注解并支持SPEL表达式”这篇文章对大家有帮助,同时也希望大家多多支持编程网,关注编程网精选频道,更多相关知识等着你来学习!

--结束END--

本文标题: 如何使用Springboot自定义注解并支持SPEL表达式

本文链接: https://www.lsjlt.com/news/322756.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何使用Springboot自定义注解并支持SPEL表达式
    这篇文章主要介绍了如何使用Springboot自定义注解并支持SPEL表达式,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。Springboot自定义注解,支持SPEL表达式举...
    99+
    2023-06-29
  • 使用Springboot自定义注解,支持SPEL表达式
    目录Springboot自定义注解,支持SPEL表达式1.自定义注解2.使用AOP拦截方法,解析注解参数自定义注解结合切面和spel表达式自定义一个注解自定义一个service类,在...
    99+
    2024-04-02
  • 支持SpEL表达式的自定义日志注解@SysLog介绍
    目录序言预期思路过程结果序言 之前封装过一个日志注解,打印方法执行信息,功能较为单一不够灵活,近来兴趣来了,想重构下,使其支持表达式语法,以应对灵活的日志打印需求。 该注解是方法层面...
    99+
    2024-04-02
  • SpringAOP如何在注解上使用SPEL表达式注入对象
    目录在注解上使用SPEL表达式注入对象场景描述具体案例补充Spring属性注入方式之SPEL表达式在注解上使用SPEL表达式注入对象 场景描述 在平时开发中,我们经常通过定义一些注解...
    99+
    2024-04-02
  • 如何在SpringBoot环境下使得自定义的注解能够使用${xxx}表达式
    如何在SpringBoot环境下使得自定义的注解能够使用${xxx}表达式,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。相关依...
    99+
    2024-04-02
  • 在@Value注解内使用SPEL自定义函数方式
    目录@Value注解内使用SPEL自定义函数自定义注解支持SpEL表达式1.定义日志注解2.定义spel解析工具类3.定义切面类4.方法上使用日志注解@Value注解内使用SPEL自...
    99+
    2024-04-02
  • 基于spring @Cacheable 注解的spel表达式该如何解析执行
    今天就跟大家聊聊有关基于spring @Cacheable 注解的spel表达式该如何解析执行,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。日常使用中spring...
    99+
    2023-06-22
  • C++ lambda 表达式如何定义和使用?
    c++++ lambda 表达式是匿名函数,用于内联定义函数,使用语法:[capture list](parameters) -> return_type {函数体}。它们可以捕获...
    99+
    2024-04-17
    c++
  • 详解如何在Spring Security中自定义权限表达式
    目录1. SpEL 回顾2. 如何自定义3. 自定义 ExpressionRoot1. SpEL 回顾 经过上篇文章的学习,小伙伴们已经知道了,在 Spring Security 中...
    99+
    2024-04-02
  • SpringBoot如何使用自定义注解实现接口限流
    目录使用自定义注解实现接口限流1、自定义限流注解2、限流类型枚举类3、限流 Lua 脚本4、限流切面处理类 5、使用与测试SpringBoot工程中限流方式1、google...
    99+
    2024-04-02
  • springboot中如何使用自定义注解实现加解密及脱敏方式
    这篇文章主要介绍springboot中如何使用自定义注解实现加解密及脱敏方式,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!自定义注解实现加解密及脱敏定义自定义注解@Documented@Target({Element...
    99+
    2023-06-22
  • 如何使用SpringBoot自定义starter
    这篇文章主要介绍了如何使用SpringBoot自定义starter,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。springboot是什么springboot一种全新的编程规...
    99+
    2023-06-14
  • Java中自定义注解如何使用
    本文小编为大家详细介绍“Java中自定义注解如何使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java中自定义注解如何使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。什么是注解在早期的工作的时候 ,自定义...
    99+
    2023-07-05
  • springboot如何读取自定义properties并注入到bean中
    目录读取自定义properties注入到beanspringboot启动日志如下springboot bean实例化和属性注入过程springboot版本(2.0.4 RELEASE...
    99+
    2024-04-02
  • 如何在SpringBoot项目中的自定义配置添加IDE支持
    这篇文章将为大家详细讲解有关如何在SpringBoot项目中的自定义配置添加IDE支持,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Application.java:application....
    99+
    2023-06-06
  • 如何使用自定义注解实现redisson分布式锁
    这篇文章主要讲解了“如何使用自定义注解实现redisson分布式锁”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何使用自定义注解实现redisson分布式锁”吧!自定义注解实现rediss...
    99+
    2023-06-29
  • 用 C++ lambda 表达式自定义排序规则如何实现?
    使用 c++++ lambda 表达式自定义排序规则,可灵活定义排序逻辑。语法为:[capture list](parameters) -> return type { body ...
    99+
    2024-04-17
    c++ lambda 排列
  • 使用Spring AOP 如何实现自定义注解
    这期内容当中小编将会给大家带来有关使用Spring AOP 如何实现自定义注解,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。在Maven中加入以下以依赖:<!-- Spring AOP + Aspe...
    99+
    2023-05-31
    springaop 注解
  • springboot使用自定义注解实现aop切面日志
    平时我们在开发过程中,代码出现bug时为了更好的在服务器日志中寻找问题根源,会在接口的首尾打印日志,看下参数和返回值是否有问题。但是手动的logger.info() 去编写时工作量较...
    99+
    2024-04-02
  • 使用自定义注解实现redisson分布式锁
    目录自定义注解实现redisson分布式锁自定义注解aop解析注解service中使用注解加锁使用redisson分布式锁应用应用场景Redisson管理类分布式锁测试类自定义注解实...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作