自定义注解1-实现spel表达式
时间:2022-07-28
本文章向大家介绍自定义注解1-实现spel表达式,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
开发中多多少少会使用spel,spel是Spring3引入了Spring表达式语言(Spring Expression Language,SpEL),在一些配置中,注解中经常用到,可谓是神器。比如说spring中的@Cacheable注解,其中key、unless等属性都支持Spel。举个例子:
@Cacheable(key="#user.name + '_' + #user_phone", unless="#user.age > 18")
public Product getProduct(User user){
// do something...
}
上面spel表达的意思就是,缓存使用的key由入参属性name和phone组成,当用户的年纪大于18岁时,不进入缓存。
但是@Cacheable其中cacheNames这个属性不支持Spel,很痛苦。所以我准备“重复造一次轮子”(解决cacheNames的问题还是有别的方法解决的,所以本文纯属技术交流)
自定义注解
目的很明确,定义一个支持spel的注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Interest{
String key();
String unless();
}
@Interest(key = "#user.name + #user.phone", unless = "#user.age > 18")
public void interest(User user){
// ....
}
实现Spel
package com.yzker.interest.core.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
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;
/**
* @author far.liu
*/
@Component
@Aspect
public class InterestResolveELAspect {
private static final Logger logger = LoggerFactory.getLogger(InterestResolveELAspect.class);
ExpressionParser parser = new SpelExpressionParser();
LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
@Around("@annotation(anno)")
public Object invoked(ProceedingJoinPoint pjp, Interest anno) throws Throwable {
Object[] args = pjp.getArgs();
Method method = ((MethodSignature) pjp.getSignature()).getMethod();
String[] params = discoverer.getParameterNames(method);
EvaluationContext context = new StandardEvaluationContext();
for (int len = 0; len < params.length; len++) {
context.setVariable(params[len], args[len]);
}
String keySpel = anno.key();
Expression keyExpression = parser.parseExpression(keySpel);
String key = keyExpression.getValue(context, String.class);
String unlessSpel = anno.unless();
Expression unlessExpression = parser.parseExpression(unlessSpel);
Boolean unless = unlessExpression.getValue(context, Boolean.class);
logger.info("call InterestResolveELAspect.invoked, keySpel:[{}], resolvedKey:[{}], unlessSpel:[{}], resolvedUnless:[{}]"
, keySpel, key, unlessSpel, unless);
// todo cache ...
return pjp.proceed();
}
}
以上代码是由aop解析spel,缓存处理逻辑未实现,本文重点在解析spel,不在于造轮子,如果不到万不得已不要尝试自己造轮子。
说一下关于cacheNames不支持spel。首先得明白cacheNames是干嘛的,在这个注解中,它主要用来配置每一类型的缓存数据过期时间。其实你可以定义一个全局默认的cacheName,所有缓存都使用它,而过期时间你在别的地方修改。不管你是用redis缓存,还是guava缓存,它总的有一个put进缓存的方法,其实你重写它本身的put方法,这里面一般会有过期时间的,你可以在这里根据你的业务场景修改过期时间。
- 从插件重构看如何提升测试质量与效率
- 巧用WinRAR+Javascript解决activeX的自动安装问题
- 在网页中实现QQ的屏幕截图功能
- Activity之间传递参数
- linux下rsync和tar增量备份梳理
- 重温Delphi之:面向对象
- Android新手之旅(15) Win7下配置遇到的问题
- 重温Delphi之:如何定义一个类
- Android新手之旅(2) 新手问题
- Android新手之旅(2) 新手问题
- Android新手之旅(9) 自定义的折线图
- 2018春节抢票攻略:不仅仅是12306微信小程序启用
- Android新手之旅(9) 自定义的折线图
- Android新手之旅(11) 在现有页面中插入新的view
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 前端踩坑系列《二》
- Markdown语法
- 配置ssh免密登陆,并使用命令行与服务器交互
- 使用scp进行与服务器的文件交互(上传和下载)
- Python 技术篇-文件操作:本地文件重命名
- 3种方法加密Python文件
- 用两个栈实现队列
- Python+selenium 自动化-selenium自带的截图功能
- PyQt5 技巧篇-便于文字排版的等宽字体推荐,中文为英文两倍宽字体
- php List()函数及json_encode时无法转为数组的问题
- Python 技术篇-邮件发送并展示本地图片
- PHP变量传递值的方法
- Python 技术篇-邮件发送各种类型的附件
- PHP循环语句
- Markdown简易教程