Java切面中各个方法对象、参数对象、反射以及注解的分析
迪丽瓦拉
2024-03-19 03:26:27
0

说明:
本文以环绕切面配合反射、注解为示例

	@Around(value = "cutMethods() && withAnnotationMethods()")public Object around(ProceedingJoinPoint point) throws Throwable {long startTime = System.currentTimeMillis();//通过请求上下文持有者,获取 Servlet 容器对象ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();//通过 Servlet 容器对象获取 request 请求对象HttpServletRequest request = attributes.getRequest();MethodSignature methodSignature = (MethodSignature) point.getSignature();Method method = methodSignature.getMethod();BusinessLock lockAnnotation = method.getAnnotation(BusinessLock.class);//获取所有参数的类型和名称Parameter[] parameters = method.getParameters();//获取所有参数的值Object[] args = point.getArgs();//获取全部参数信息数组、以及每个参数的全部注解信息数组Annotation[][] parameterAnnotations = method.getParameterAnnotations();//方法执行之前动作,等效于@BeforeObject res = point.proceed();//方法执行之后动作,等效于@Afterlog.info("执行方法耗时(毫秒)为:" + (System.currentTimeMillis() - startTime));return res;}

一、环绕增强切入

1、通过请求上下文持有者,获取 Servlet 容器对象
【1】ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(),获取 Servlet 容器信息对象

2、通过 Servlet 容器对象获取 request 请求对象
【1】HttpServletRequest request = attributes.getRequest(),获取 request 请求对象
【2】通过 HttpServletRequest request 对象可以获取请求头、请求方法、请求路径、请求参数等信息

3、@Around(value = "xxx() && xxx()")
【1】value值为切入条件,可以切入controller层、service层、指定注解等
【2】public Object around(ProceedingJoinPoint point) 入参为切入点对象,里面包括切入方法的所有信息,包括方法名、参数信息、返回信息等

4、获取方法对象
【1】MethodSignature methodSignature = (MethodSignature) point.getSignature(),通过切入点对象获取方法签名对象
【2】Method method = methodSignature.getMethod(),从方法签名对象中获取方法对象

5、获取参数的类型和名称
【1】Parameter[] parameters = method.getParameters(),获取参数个数、类型、名称
【2】method.getParameters() 的参数个数、索引顺序与 point.getArgs() 是一致的

6、获取所有参数的值
【1】Object[] args = point.getArgs(),获取参数的值信息,注意是 值
【2】point.getArgs() 的参数个数、索引顺序与 method.getParameters() 是一致的

7、获取全部参数信息数组、以及每个参数的全部注解信息数组
【1】Annotation[][] parameterAnnotations = method.getParameterAnnotations(),返回的是个二维数组,第一维度包含切入方法的全部参数信息、第二维度包含每个参数对应的注解信息
【2】验证示例如下:
验证用 api 代码

	@ApiOperation(value = "公共测试接口")@GetMapping("/testPublicApi")public CommonResult testPublicApi(@BusinessLockKey Long id, @BusinessLockKey @FieldConvert String code, String name) {System.out.println("主线程运行结束");return success("成功!");}

验证用 aop 代码

//获取参数的类型和名称
Parameter[] parameters = method.getParameters();//获取全部参数信息数组、以及每个参数的全部注解信息数组
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
for (int i = 0; i < parameterAnnotations.length; i++) {System.out.println("第" + (i + 1) + "个参数:" + parameters[i].getName() + " 有" + parameterAnnotations[i].length + "个注解");Annotation[] parameterAnnotationss = parameterAnnotations[i];for (int j = 0; j < parameterAnnotationss.length; j++) {//System.out.println("第" +(i+1)+ "个参数:"+parameters[i].getName()+" 的第" +(j+1)+ "个注解为:" + parameterAnnotationss[j]);System.out.println("第" + (i + 1) + "个参数:" + parameters[i].getName() + " 的第" + (j + 1) + "个注解为:" + parameterAnnotationss[j]);}
}

输出:

第1个参数:id 有1个注解
第1个参数:id 的第1个注解为:@com.hkl.annotation.BusinessLockKey(name="")
第2个参数:code 有2个注解
第2个参数:code 的第1个注解为:@com.hkl.annotation.BusinessLockKey(name="")
第2个参数:code 的第2个注解为:@com.hkl.annotation.FieldConvert(codeType="", value="")
第3个参数:name 有0个注解
主线程运行结束

二、总结

1、Java Aspect 切面可以定义规则切入任意切入点

2、Java切面可以通过切入点对象 ProceedingJoinPoint 配合反射、注解、方法签名对象、参数对象等灵活获取各种信息,从而对请求执行业务前后进行不同的拦截处理动作

3、Java Aspect 中最重要、也是最常用的 @Around 环绕增强切入,其中切入点对象的方法 point.proceed() 为执行我们的业务方法

相关内容