spring aop基于注解开发(@Around)

上接:spring aop创建工程基于注解开发(@Before、@After、@AfterReturning、 @AfterThrowing)

概述

本文介绍 Around 通知

修改 Logger 类

增加下面方法:

@Around("pt()")
public void aroundPrint(){
    System.out.println("======around");
}

完整代码

@Component
@Aspect
public class Logger {

    @Pointcut("execution(* top.malaoshi.service.*.*(..))")
    public void pt(){

    }
    @Before("pt()")
    public void beforePrint(){
        System.out.println("=======before");
    }
    @After("pt()")
    public void afterPrint(){
        System.out.println("======after");
    }
    @AfterReturning("pt()")
    public void afterReturningPrint(){
        System.out.println("======afterReturning");
    }
    @AfterThrowing("pt()")
    public void afterThrowingPrint(){
        System.out.println("======异常通知afterThrowingPrint");
    }
    @Around("pt()")
    public void aroundPrint(){
        System.out.println("======around");
    }
}

修改 UserSrvImpl 类

让该类所有的方法都能 执行成功

完整代码

@Service
public class UserSrvImpl implements IUserService {

    public UserSrvImpl(){
        System.out.println("UserSrvImpl构造方法");
    }
    public void save(String username,String password){
//        System.out.println("UserSrvImpl保存 报错");
//        throw new RuntimeException("UserSrvImpl保存 报错");
        System.out.println("UserSrvImpl保存 "+username+"-"+password);
    }
    public int update(){
        System.out.println("UserSrvImpl修改 ");
        return 1;
    }
    public int delete(String id){
        System.out.println("UserSrvImpl删除 "+id);
        return 2;
    }
}

测试-有问题

主启动类

public class Main {
    public static void main(String[] args) {
        ApplicationContext ac=new AnnotationConfigApplicationContext(ApplicationConfig.class);

        IUserService srv=(IUserService)ac.getBean("userSrvImpl");
        srv.save("李雷","123456");
//        srv.update();
    }
}

执行结果如下:

======around
======after
======afterReturning

发现没有执行目标方法

解决问题

around环绕通知 ProceedingJoinPoint 形参

需要在 环绕方法中传入形参 ProceedingJoinPoint ,该类有以下作用:

  1. 通过该类获取 传入目标方法的形参
  2. 通过该类 调用目标方法
  3. 通过该类 获取目标方法的返回结果

修改Logger类的 aroundPrint 方法

@Around("pt()")
public Object aroundPrint(ProceedingJoinPoint pjp) throws Throwable {
    Signature s=jp.getSignature();
    System.out.println("======around开始 "+"调用 " + s.getDeclaringTypeName()+"."+s.getName()
                + " 方法,参数:" + Arrays.toString(jp.getArgs()));
    //获取传入的目标方法的参数
    Object[] array=pjp.getArgs();
    //调用目标方法,并返回结果
    Object res=null;
    try {
        res = pjp.proceed(array);
        System.out.println("======around结束");
    }catch (Throwable e){
        System.out.println("======around捕捉异常");
        throw e;
    } finally {
        System.out.println("方法结束执行");
    }
    return res;
}

注意: pjp.proceed() 方法会抛出异常,不要 catch 该异常,否则不会触发 @AfterThrowing 通知

测试-执行成功

执行结果如下:

UserSrvImpl构造方法
======around开始
=======before
UserSrvImpl保存 李雷-123456
======around结束
======after
======afterReturning

执行成功顺序

  1. around 开始
  2. before
  3. 目标方法
  4. around 结束
  5. after
  6. afterReturning

测试-执行抛出异常

修改 UserSrvImpl 的 save()方法

让其抛出异常

public void save(String username,String password){
    System.out.println("UserSrvImpl保存 报错");
    int i=1/0;
//        System.out.println("UserSrvImpl保存 "+username+"-"+password);
}

执行

执行结果如下:

======around开始
=======before
UserSrvImpl保存 报错
======around捕捉异常
======after
======异常通知afterThrowingPrint

执行抛出异常的顺序

  1. around 开始
  2. before
  3. 目标方法
  4. around 捕捉异常
  5. after
  6. afterThrowing

总结

一般使用 @Around 注解可以代替 @Before、@After、@AfterReturning、@AfterThrowing


原文出处:/show_1IX39gZ2Fa8.html