Java自定义注解实战-接口的幂等性
Posted 江月曾照人
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java自定义注解实战-接口的幂等性相关的知识,希望对你有一定的参考价值。
Java自定义注解实战
什么是注解?
注解是写在.java
文件中,使用@interface
作为关键字的,所以注解也是Java的一种数据类型;注解从JDK1.5
开始引入的一个特性,可以对类、接口、方法、属性、方法参数等进行注解。
注解的作用
注解主要有以下四个作用:
- 生成文档:生成
javadoc
文档,如@Documented
; - 编译检查:在编译期间对代码进行检查验证,如
@Override
; - 编译时处理:编译时对代码进行特定的处理,如
@Data
; - 运行时处理:运行时对代码进行特定的处理,如
@Slf4j
;
注解与反射
定义注解后,我们可以通过反射java.lang.reflect
机制获取注解的内容。注:只有当注解的使用范围定义为Runtime
才能通过反射获取。
以下为具体接口API:
方法说明 | 方法 |
---|---|
获取某个类型的注解 | public <A extends Annotation> A getAnnotation(Class<A> annotationClass); |
获取所有注解(包括父类中被Inherited修饰的注解) | public Annotation[] getAnnotations(); |
获取声明的注解(不包括父类中被Inherited修饰的注解) | public Annotation[] getDeclaredAnnotations(); |
判断某个对象上是否被某个注解进行标注 | public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) |
获取某个类声明的所有字段 | public Field[] getDeclaredFields() throws SecurityException; |
获取某个方法 | public Method getMethod(String name, Class<?>... parameterTypes); |
自定义注解实战
结合AOP
可以进行权限控制,日志输出及幂等性校验等;
以幂等性1校验举例子:
第一步:定义注解
package com.wedjg.cloud.finance.aspect.idem;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EnableIdem {
/**
* 幂等时间间隔(秒)
* @return
*/
int expired() default 3;
}
第二步:使用注解
@PostMapping("test")
@EnableIdem
public CommonResult test(@RequestBody DemoDTO dto) {
financeService.test(dto);
return CommonResult.success(true);
}
第三步:编写切面
@Aspect
@Component
public class IdempotentAspect {
public static final Log log = LogFactory.get();
public static final String KEY = "Idem|";
@Before("@annotation(com.wedjg.cloud.aspect.idem.EnableIdem)")
public void handle(JoinPoint joinPoint) throws Exception{
// 获取参数值
Object[] args = joinPoint.getArgs();
//构造缓存的key
//此处使用的是方法路径 + 参数的hashcode 作为key,在个别情况下有可能会重复
//在实际使用时应根据业务调整
StringBuilder sb = new StringBuilder();
for (Object arg : args) {
sb.append(Convert.toStr(arg));
}
String methodPath = joinPoint.getSignature().getDeclaringTypeName() + CharUtil.DOT + joinPoint.getSignature().getName();
String redisKey = KEY + methodPath + sb.toString().hashCode();
//将key存到redis中。要注意保证 setnx 和 expired 的原子性;
//若key已存在,说明在expired()的时间范围内已经请求过。当前请求为重复请求;
//若key不存在,则把当前key设置到redis中,并设置过期时间。
//获取注解的信息
EnableIdem enableIdem = this.getDeclaredAnnotation(joinPoint);
if(JedisUtil.setnxAndExpire(redisKey, enableIdem.expired(), "1") == 0L) {
throw new BaseException("操作过于频繁,请稍后再试!");
}
}
/**
* 获取方法中声明的注解
*
* @param joinPoint
* @return
* @throws NoSuchMethodException
*/
public EnableIdem getDeclaredAnnotation(JoinPoint joinPoint) throws NoSuchMethodException {
// 获取方法名
String methodName = joinPoint.getSignature().getName();
// 反射获取目标类
Class<?> targetClass = joinPoint.getTarget().getClass();
// 拿到方法对应的参数类型
Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
// 根据类、方法、参数类型(重载)获取到方法的具体信息
Method objMethod = targetClass.getMethod(methodName, parameterTypes);
// 拿到方法定义的注解信息
EnableIdem annotation = objMethod.getDeclaredAnnotation(EnableIdem.class);
// 返回
return annotation;
}
}
参考文章
- Java自定义注解Annotation详解
- Java 基础 - 注解机制详解
- Redis同时操作setnx和expire
- 用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用 ↩
以上是关于Java自定义注解实战-接口的幂等性的主要内容,如果未能解决你的问题,请参考以下文章
SpringBoot自定义注解+AOP+redis实现防接口幂等性重复提交,从概念到实战