一、示例
① 如下代码,自定义一个参数注解@Test,并将其使用到方法参数上,用于标注需要检验的参数
/**
* 自定义注解,用于参数
*/
@Target(PARAMETER)
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Test{
}
/**
* 接口层,使用使用@Test注解标记参数
*/
@RestController
@RequestMapping("/v1/test")
public class TestController {
@PostMapping(value = "/email", produces = "application/json")
public String send(@RequestBody @Test MailSendDTO mailSendDTO) {
//TODO 业务处理
return "SUCCESS";
}
}
② 通过切面拦截该方法,从连接点获取signature,并将signature强转为MethodSignature,从而从MethodSignature对象可以获取拦截的方法对象以及方法参数注解
@Aspect
@Configuration
public class ValidateAop {
/**
* 切点配置,表达式, 在com.laoxi.test.controller包下,所有的类public的任意参数的方法
*/
@Pointcut("execution(public * com.laoxi.test.controller.*.*(..))")
public void validate(){}
@Before("validate()")
public void doBefore(JoinPoint joinPoint){
Object[] params = joinPoint.getArgs();
if(params.length == 0){
return;
}
//获取方法,此处可将signature强转为MethodSignature
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
//参数注解,1维是参数,2维是注解
Annotation[][] annotations = method.getParameterAnnotations();
for (int i = 0; i < annotations.length; i++) {
Object param = params[i];
Annotation[] paramAnn = annotations[i];
//参数为空,直接下一个参数
if(param == null || paramAnn.length == 0){
continue;
}
for (Annotation annotation : paramAnn) {
//这里判断当前注解是否为Test.class
if(annotation.annotationType().equals(Test.class)){
//校验该参数,验证一次退出该注解
//TODO 校验参数
break;
}
}
}
}
}
二、debug
通过debug代码:
可发现连接点实际为MethodInvocationProceedingJoinPoint对象,连接点中的signature则为MethodSignatureImpl对象,是MethodInvocationProceedingJoinPoint的内部类。
三、类图及源码
MethodInvocationProceedingJoinPoint类图,顶级实现了JoinPoint(以后再使用切面的时候,可以看看其他类里面都扩展了哪些方法可以直接使用)
MethodSignatureImpl类图,顶级实现了Signature(以后再使用切面的时候,可以看看其他类里面都扩展了哪些方法可以直接使用)