在上一篇文章基于AOP和Redis实现的简易版分布式锁中我们已经介绍了实现一个简易版的分布式锁。
那么本文主要来讲,如何将注解LockAnnotation和LockParamAnnotation合二为一,在LockAnnotation添加lockKey()方法来实现原本需要通过LockParamAnnotation来实现的锁的唯一主键。
本次优化主要是引入了Spel。
LockAnnotation主要改动就是添加了lockKey()方法。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface LockAnnotation {
/**
* 加锁的key的前缀
*
* @return
*/
String lockField() default "";
/**
* 锁自动释放时间,单位s
*
* @return
*/
int lockTime() default 3;
/**
* 加锁的key的值
* @return
*/
String lockKey() default "";
}
LockAspect主要改动是获取lockKey的方式,和之前不同的是目前lockKey的值的由注解上的lockKey()中的spel语法实现。
ExpressionParser parser = new SpelExpressionParser();
LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
EvaluationContext context = new StandardEvaluationContext();
Object[] args = joinPoint.getArgs();
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
String[] params = discoverer.getParameterNames(signature.getMethod());
for (int len = 0; len < params.length; len++) {
context.setVariable(params[len], args[len]);
}
Expression expression = parser.parseExpression(lockAnnotation.lockKey());
String lockKey = expression.getValue(context, String.class);
使用方式和之前的区别也只在于两个注解合并。lockKey的命名尽量保持'x='+#x的方式。
如果变量是个对象,需要获取到对象中的值,例如是order对象中的orderSn,可以通过order.orderSn方式获取。
@LockAnnotation(lockField = "lock", lockTime = 10, lockKey = "'orderSn='+#orderSn")
public Integer lock(String action, String orderSn) {
System.out.println(action);
return 1;
}
需要注意的是,常量'orderSn='需要用单引号',否则会被当做是赋值语法,而#后面的orderSn只要和方法中的变量名orderSn保持一直就可以了。
最后感谢好友樊金龙给的合并注解的建议,这才有了本次优化。
欢迎大家继续提建议,如有采纳,会在文末感谢。
网友评论