AspectJ——切入点语法(5)之限制连接点的作用域

限制连接点的作用域

在定义切入点的时候,我们经常遇到的需求是:基于所关注的程序作用域,限制捕获连接点的范围。

本节将介绍within以及withincode的用法。within可以指定切入点的作用域在包中或者类中,withincode可以通过方法签名限制连接点的作用域在方法中。

0.捕获特定类中的所有连接点

首先,我们使用within(TypePattern)切入点来捕获特定类中的所有连接点,它的语法如下:

pointcut [切入点名字](想要获取的参数): within(类名);

要注意的几点:

  1. within(TypePattern)切入点捕获指定类作用域中的所有连接点。
  2. within(TypePattern)切入点极少单独使用,它通常与其他切入点结合使用,用于减少将要捕获连接点。
  3. within(TypePattern)可以包含通配符,用于选择不同类上的一系列连接点。

我们在Test9包下进行测试。

这里写图片描述

首先创建业务类Service,如下:

package Test9;

public class Service {
    protected static String name = "Gavin John";
    private String firstname = "Gavin";
    private String lastname = "John";

    public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public String getLastname() {
        return lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    public void test(int a, float b) {
        System.out.println("a + b = " + (a + b));
    }
}

接着,创建测试类Main,进行测试:

package Test9;

public class Main {
    public static void main(String[] args) {
        Service service = new Service();
        System.out.println(service.getFirstname());
        System.out.println(service.getLastname());
        service.setLastname("Jack");

        service.test(3, 3.4F);
    }
}

最后,我们创建切面WithinAspect,如下:

package Test9;

public aspect WithinAspect {
    pointcut withinService(): within(Service);

    before(): withinService(){
        System.out.println();
        System.out.println(thisJoinPoint.getKind());
        System.out.println("Signature: " + thisJoinPoint.getSignature());
        System.out.println("Source Line: " + thisJoinPoint.getSourceLocation());
    }
}

在该切面中,我们创建了withinService切入点,该切入点捕获所有在Service类中的连接点。并且为该切入点织入前置通知,在通知中我们打印了当前连接点的类型、签名以及在源代码中的位置。

运行结果如下:

这里写图片描述

由于Service类中的连接点非常多,所以这里只截取了一部分运行结果。从运行结果中可以看到,我们捕获了出现在Service类中的所有连接点,包含staticinitializationfield-setconstructor-execution等各种连接点。

1.捕获特定包中的所有连接点

在上例中,我们捕获了Service类中的所有连接点,现在假如我们要捕获Test9包下的所有连接点,该怎么做呢?

这里我们只需要简单修改切入点即可,如下,我们使用通配符表达式Test9.*来表示Test9包下的所有类。

package Test9;

public aspect WithinAspect {
    pointcut withinService(): within(Test9.*);

    before(): withinService(){
        System.out.println();
        System.out.println(thisJoinPoint.getKind());
        System.out.println("Signature: " + thisJoinPoint.getSignature());
        System.out.println("Source Line: " + thisJoinPoint.getSourceLocation());
    }
}

但是,如果我们此时运行程序,会得到出错的结果,如下:

这里写图片描述

报了NoAspectBoundException异常,这是为什么呢?这是因为,我们的切面WithinAspect也位于Test9包下,所以我们的切入点表达式Test9.*自然也包含了切面本身,也就是说切面也会捕获切面自身的切入点,并为其织入通知。

所以,在切面初始化的时候,切面初始化的连接点被捕获到,这时候要运行通知代码,而此时切面初始化并没有完成,通知自然也就不存在,所以就抛出了异常。简单来说,这个异常的原因就是,切面来横切并通知切面自身的时候出现了矛盾的情况。

我们通过!within(TypePattern)来将该切面排除在外即可,这里感叹号!表示逻辑非,即将其后面表达式的意义取反。如下:

package Test9;

public aspect WithinAspect {
    pointcut withinService(): within(Test9.*) && !within(WithinAspect);

    before(): withinService(){
        System.out.println();
        System.out.println(thisJoinPoint.getKind());
        System.out.println("Signature: " + thisJoinPoint.getSignature());
        System.out.println("Source Line: " + thisJoinPoint.getSourceLocation());
    }
}

within(Test9.*) && !within(WithinAspect)表示在Test9包下的所有类,但是排除了WithinAspect。此时可以成功运行。运行结果就是捕获了所有在Service类和Main类中的连接点。这里展示了一小部分结果:

这里写图片描述

2.捕获特定方法内的所有连接点

我们使用withincode(Signature)切入点来捕获与特定签名匹配的方法内的所有连接点。其语法是:

pointcut [切入点名字](要获取的参数): withincode(<可选的修饰符> 类名.方法名(参数列表));

要注意的几点是:

  1. withincode(Signature)切入点指定了特定方法作用域内的所有连接点。
  2. withincode(Signature)切入点很少单独使用。一般与其他切入点结合使用,用于减少将要捕获连接点。
  3. Signature可以包含通配符,用于选择跨越不同类不同方法上的一系列连接点。
  4. withincodewithin的区别就是withincode用于指定方法,而within用于指定类。

我们在Test10包下进行测试。

这里写图片描述

其中Service类与Main类与上例中的一样,这里不再赘述。我们在这里新建切面WithincodeAspect,如下:

package Test10;

public aspect WithincodeAspect {
    pointcut withinCodePointcut(): withincode(* Main.main(*));

    before(): withinCodePointcut(){
        System.out.println();
        System.out.println(thisJoinPoint.getKind());
        System.out.println("Signature: " + thisJoinPoint.getSignature());
        System.out.println("Source Line: " + thisJoinPoint.getSourceLocation());
    }
}

在该切面中,我们使用withincode(* Main.main(*))捕获了Main类中的main方法中的所有连接点。这里截取一部分运行结果:

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值