概述
Java自定义注解一般使用场景为:自定义注解+拦截器或者AOP,使用自定义注解来自己设计框架,使得代码看起来非常优雅。
本文主要介绍使用自定义注解+AOP来实现。
一、注解概念
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
二、注解分类
在Java中,注解分为两种,元注解和自定义注解。
三、常用元注解作用 (jdk提供的元注解)
1.@Target:描述当前注解能够作用的位置
ElementType.TYPE:可以作用在类上
ElementType.METHOD:可以作用在方法上
ElementType.FIELD:可以作用在成员变量上
2.@Retention: 描述注解被保留到的阶段
SOURCE < CLASS < RUNTIME
SOURCE:表示当前注解只在代码阶段有效
CLASS:表示该注解会被保留到字节码阶段
RUNTIME:表示该注解会被保留到运行阶段 JVM
自定义的注解:RetentionPolicy.RUNTIME
3.@Documented:描述注解是否被抽取到JavaDoc api中
4.@inherited:描述注解是否可以被子类继承
四、示例-AOP反射获取注解
1、第一步自定义注解
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author
* @Date 2022/7/13 16:45
* @Description
* @Version 1.0
*/
@Inherited
@Documented
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckSign {
/**
* 设定名称
**/
String name() default "";
/**
* 设定默认验签长度
**/
int signLength() default 2;
}
2、第二步通过AOP拦截处理
注:导包缺少自定义异常、验签工具类等请求对象
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
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.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author :
* @date :Created in 19:54 2022/7/13
* @description :
* @version: 1.0
*/
@Component
@Scope
@Aspect
@Slf4j
public class CheckSignInterceptor {
@Resource
protected HttpServletRequest httpServletRequest;
/**
* 定义切入点
* @Author
* @Date Created in 19:54 2022/7/13
* @Description com.*.annotation.CheckSign为自定义注解类包全路径
* @param
* @return void
**/
@Pointcut("@annotation(com.*.annotation.CheckSign)")
public void limit() {
}
@Around("limit()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws IOException {
Signature signature = proceedingJoinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
CheckSign checkSign = methodSignature.getMethod().getDeclaredAnnotation(CheckSign.class);
int signLength = checkSign.signLength();
String name = checkSign.name();
TestRequest testRequest = new ObjectMapper().readValue(httpServletRequest.getInputStream(), TestRequest.class);
Object obj = null;
if (MessageDigest5Util.isPass(testRequest, signLength)) {
try {
obj = proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
} else {
log.warn("方法:{},{}签名校验失败", name, ExceptionCode.UNAUTHORIZED_ACCESS);
throw new CommonException(ExceptionCode.UNAUTHORIZED_ACCESS.getCodeValue(), "签名校验失败");
}
return obj;
}
}