AspectJ——切入点语法(2)之捕获异常处理上的连接点

捕获异常处理上的连接点

在Java中抛出异常时,会将其向上传递给调用链,直到它被try/catch块中的catch语句处理,或者它到达Java运行库并在控制台上引发一条出错的消息。如果捕获到Java异常,就会把该异常作为一个对象传递给相应的catch语句,在其中处理该异常。

使用切面可以捕获异常的处理,其应用的场景可以是:除了catch块的正常异常处理行为之外,使用切面还需要做某些事情;或者干脆使用切面代替catch块的正常行为。

0.捕获特定异常的处理

假设你想捕获程序对特定异常的处理。AspectJ提供了handler(异常类)切入点来实现这一功能。它的语法是:

pointcut [切入点名字](参数列表): handler(异常类);

需要注意的几点是:

  • hander(异常类)捕获的连接点是catch语句。也就是在程序捕捉异常的地方捕获连接点,而不是在引发异常的地方。
  • 此处的异常类为Throwable及其子类。
  • handler(异常类)只能使用before()指定前置通知,不支持其他形式的通知。
  • 此处的异常类也可以使用通配符,用于选择不同类上的一系列连接点。

下表表示了异常类使用通配符的示例:

带有通配符的异常类 描述
mypackage..* 捕获mypackage包及其子包中的类的连接点
MyClass+ 捕获MyClass类及其任何子类中的连接点

我们在Test5包下做一个简单的测试。

这里写图片描述

首先我们自定义异常MyException,使其继承自Exception,内容可以为空。

package Test5;

public class MyException extends Exception {
}

接着,我们创建业务类Service,并在其中定义test方法,在该方法中,我们抛出自定义的MyException异常,并且使用try/catch语句来捕获。

package Test5;

public class Service {
    private String name;

    public Service(String name) {
        this.name = name;
    }

    public void test(){
        try {
            throw new MyException();
        } catch (MyException e) {
            System.out.println("MyException Catch 处理语句...");
        }
    }

    @Override
    public String toString() {
        return "Service{" +
                "name='" + name + '\'' +
                '}';
    }
}

接着,我们定义主方法来测试,如下Main类。

package Test5;

public class Main {
    public static void main(String[] args) {
        Service service = new Service("Gavin");
        service.test();
    }
}

如果此时不添加切面,其运行效果是这样的:

这里写图片描述

接着我们添加HandlerAspect切面。如下:

package Test5;

public aspect HandlerAspect {
    pointcut handlerPointcut(): handler(MyException);

    before(): handlerPointcut(){
        System.out.println("MyException 切面处理...");
        System.out.println("Signature: " + thisJoinPoint.getSignature());
        System.out.println("Source Line: " + thisJoinPoint.getSourceLocation());
    }
}

可以看到,我们在切面中定义了切入点,名字为handlerPointcut,使用handler(MyException)切入点语法,该切入点捕获对MyException异常的处理。我们对该切入点织入了前置通知,在通知中,我们打印了连接点的Signature和连接点在源代码中的位置。

此时的运行结果如下:

这里写图片描述

通过上面的介绍,我们知道handler(异常类)也可以使用通配符,所以下述写法对于本示例来说也是可以的:

pointcut handlerPointcut(): handler(Exception+);

或者:

pointcut handlerPointcut(): handler(Test5..*);

1.捕获异常对象

在捕获方法调用连接点时,我们可以使用args原生切入点来捕获方法传入的参数,同样的,在捕获异常处理连接点时,我们也可以通过使用args原生切入点来捕获异常对象。

比如,在上例中,我们可以在切面中获取MyException异常对象。此时,要对切面做如下的修改:

package Test5;

public aspect HandlerAspect {
    pointcut handlerPointcut(MyException e): handler(MyException) && args(e);

    before(MyException e): handlerPointcut(e){
        System.out.println("MyException 切面处理...");
        System.out.println("Signature: " + thisJoinPoint.getSignature());
        System.out.println("Source Line: " + thisJoinPoint.getSourceLocation());

        e.printStackTrace();
    }
}

如代码所示,我们在切入点添加参数MyException e,并通过args(e)获取了该异常对象。在通知中,我们使用e.printStackTrace()打印出了异常信息。

运行结果如下:

这里写图片描述

2.捕获处理异常的对象

同样的,我们可以结合使用handler(异常类)this原生切入点,来获取处理异常的对象。

我们在上例的基础上添加this原生切入点,如下:

package Test5;

public aspect HandlerAspect {
    pointcut handlerPointcut(MyException e, Service service): handler(MyException) && args(e) && this(service);

    before(MyException e, Service service): handlerPointcut(e, service){
        System.out.println("MyException 切面处理...");
        System.out.println("Signature: " + thisJoinPoint.getSignature());
        System.out.println("Source Line: " + thisJoinPoint.getSourceLocation());

        System.out.println(service);
        e.printStackTrace();
    }
}

在该切面中,我们不仅获取了MyException异常对象,也获取了处理异常的对象。

运行结果如下:

这里写图片描述

猜你喜欢

转载自blog.csdn.net/gggavin/article/details/80216132