一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第22天,点击查看活动详情。
通知分类
- @Before:前置通知,在目标方法执行前执行
- @AfterReturning: 返回后通知,在目标方法执行后执行,如果出现异常不会执行
- @After:后置通知,在目标方法之后执行,无论是否出现异常都会执行
- @AfterThrowing:异常通知,在目标方法抛出异常后执行
- @Around:环绕通知,围绕着目标方法执行
理解不同通知执行时机。(下面的伪代码是用来理解单个通知的执行时机的,不能用来理解多个通知情况下的执行顺序。如果需要配置多个通知我们会选择使用Around通知,更加的清晰并且好用)
public Object test() {
before();//@Before 前置通知
try {
Object ret = 目标方法();//目标方法调用
afterReturing();//@AfterReturning 返回后通知
} catch (Throwable throwable) {
throwable.printStackTrace();
afterThrowing();//@AfterThrowing 异常通知通知
}finally {
after();//@After 后置通知
}
return ret;
}
环绕通知非常特殊,它可以对目标方法进行全方位的增强。
例如:
@Around("pt()")
public void around(ProceedingJoinPoint pjp){
System.out.println("目标方法前");
try {
pjp.proceed();//目标方法执行
System.out.println("目标方法后");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("目标方法出现异常");
}finally {
System.out.println("finally中进行增强");
}
}
获取被增强方法相关信息
我们实际对方法进行增强时往往还需要获取到被增强代码的相关信息,比如方法名,参数,返回值,异常对象等。
我们可以在除了环绕通知外的所有通知方法中增加一个JoinPoint类型的参数。这个参数封装了被增强方法的相关信息。我们可以通过这个参数获取到除了异常对象和返回值之外的所有信息。
例如:
@Before("pt()")
public void methodbefore(JoinPoint jp){
Object[] args = jp.getArgs();//方法调用时传入的参数
Object target = jp.getTarget();//被代理对象
MethodSignature signature = (MethodSignature) jp.getSignature();//获取被被增强方法签名封装的对象
System.out.println("Before方法被调用了"); }
案例:
需求:要求让所有service包下类的所有方法被调用前都输出全类名,方法名,以及调用时传入的参数
@Component
@Aspectpublic
class PrintLogAspect {
//对哪些方法增强
@Pointcut("execution(* com.springstudy.service..*.*(..))")
public void pt(){}
//怎么增强
@Before("pt()")
public void printLog(JoinPoint joinPoint){
//输出 被增强的方法所在的类名 方法名 调用时传入的参数
joinPoint.getSignature().getName()
joinPoint.getArgs()
MethodSignature signature = (MethodSignature) joinPoint.getSignature(); //类名
String className = signature.getDeclaringTypeName(); //方法名
String methodName = signature.getName(); //调用时传入的参数
Object[] args = joinPoint.getArgs();
System.out.println(className+"=="+methodName+"======"+ Arrays.toString(args));
}}