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
- 用户对于同一操作发动的一次申请或者屡次申请的后果是统一的,不会因为屡次点击而产生了副作用 ↩