前言
在微服务流行的当下,在使用Spring Cloud / Spring Boot框架开发中,AOP使用的非常广泛,尤其是@Aspect注解方式
当属最流行的,不止功能强大,性能也很优秀,还很舒心!所以本系列就结合案例
详细介绍@Aspect方式的切面
的各种用法,力求覆盖日常开发中的各种场景。
本文主要介绍@Pointcut切点表达式
的 @within和within 这两种切点指示符,结合案例,十分钟让你彻底搞懂!
@within
匹配指定类注解, 上文的@annotation是匹配指定方法注解within
匹配指定类或包
上文回顾:【Spring AOP】@Aspect结合案例详解(一): @Pointcut使用@annotation 五种通知Advice注解(已附源码)
@within
@within
匹配的是类上的注解
,匹配后 类中实现的方法都会被Advice增强。还是结合打印日志
案例实际演练一下基本用法。
完善打印日志案例
上文实现的打印日志
使用 @annotation
方式,由于是匹配方法注解
, 所以我们就需要在各个方法上定义,代码如下:
@Service
public class DemoService {
@MethodLog
public Integer divide(Integer a, Integer b) {
System.out.printf("divide方法内打印: a=%d b=%d 返回:%d %n", a, b, a / b);
return a / b;
}
@MethodLog
public Integer add(Integer a, Integer b) {
System.out.printf("add方法内打印: a=%d b=%d 返回:%d %n", a, b, a b);
return a b;
}
}
这样一来 ,当类中越来越多的方法需要打印日志时,就需要对每个方法加@MethodLog注解,所以我们做一下完善优化,替换成在 类上加注解,不管有多少方法我只需要在类上加一个 @ClassLog注解 即可,代码如下:
代码语言:javascript复制@Service
@ClassLog
public class DemoService {
public Integer divide(Integer a, Integer b) {
System.out.printf("divide方法内打印: a=%d b=%d 返回:%d %n", a, b, a / b);
return a / b;
}
public Integer add(Integer a, Integer b) {
System.out.printf("add方法内打印: a=%d b=%d 返回:%d %n", a, b, a b);
return a b;
}
}
业务逻辑代码无侵入,所以divide 和 add 方法 都不需要改变,只是将方法上@MethodLog注解去掉
,在类上增加@ClassLog注解
,这里用到的 @ClassLog注解 代码如下:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ClassLog {
}
另外,切点 @Pointcut 我们修改成:使用@within
方式,让切点匹配ClassLog注解,代码如下:
@Pointcut(value = "@within(com.tiangang.aop.ClassLog)")
public void pointCut() {
}
语法:@Pointcut(value = "@within(注解类名
)")
和上文的@annotation语法
如出一辙,完整的切面类LogAspec
代码如下:
@Component
@Aspect
public class LogAspect {
@Pointcut(value = "@within(com.tiangang.aop.ClassLog)")
public void pointCut() {
}
@Before("pointCut()")
public void before(JoinPoint joinPoint) throws NoSuchMethodException {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Class<?> clazz = joinPoint.getTarget().getClass();
Method method = clazz.getMethod(signature.getName(), signature.getParameterTypes());
System.out.printf("[前置通知]: [目标类]:%s , [方法]:%s , [入参值]:%s%n"
, clazz.getName(), method.getName(), Arrays.toString(joinPoint.getArgs()));
}
@AfterReturning(value = "pointCut()", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
Class<?> clazz = joinPoint.getTarget().getClass();
System.out.printf("[返回通知]: [目标类]:%s , [方法]:%s , [返回值]:%s%n"
, clazz.getName(), joinPoint.getSignature().getName(), result);
}
}
Advice通知
只保留了 @Before 和 @AfterReturning ,用于记录 方法签名、入参和返回值。
调用试试看:
[前置通知]: [目标类]:com.tiangang.service.DemoService , [方法]:divide , [入参值]:[10, 2] divide方法内打印: a=10 b=2 返回:5 [返回通知]: [目标类]:com.tiangang.service.DemoService , [方法]:divide , [返回值]:5
至此,基于类的打印日志就基本完善了,所有加了@ClassLog注解的类都会被Advice增加打印日志