跟我学AspectJ(四)

 
第二章          AspectJ 语言 office:office" />
 
通知 (Advice)
       通知定义几个方面的实现,以便于在特定的程序运行段执行。这些特定段可以使用命名的切点给出也可以使用匿名切点。下面是一个使用命名切点的通知的例子:
 pointcut setter(Point p1, int newval): target(p1) && args(newval)
                                         (call(void setX(int) ||
                                          call(void setY(int)));
 
 before(Point p1, int newval): setter(p1, newval) {
      System.out.println("About to set something in " + p1 +
                         " to the new value " + newval);
 }
使用匿名切点也可以实现同样的通知,如下
 before(Point p1, int newval): target(p1) && args(newval)
                                (call(void setX(int)) ||
                                 call(void setY(int))) {
      System.out.println("About to set something in " + p1 +
                         " to the new value " + newval);
 }
下面是一些不同的通知
这个before 通知在匿名切点捕捉到连接点之前运行
 before(Point p, int x): target(p) && args(x) && call(void setX(int)) {
      if (!p.assertX(x)) return;
 }
这个after 通知在匿名切点捕捉各个连接点之后运行,无论程序是正常返回还是抛出异常。
 after(Point p, int x): target(p) && args(x) && call(void setX(int)) {
      if (!p.assertX(x)) throw new PostConditionViolation();
 }
下面的after 通知在匿名切点捕捉到连接点后且仅仅在程序正常返回的情况下在运行。
 after(Point p) returning(int x): target(p) && call(int getX()) {
      System.out.println("Returning int value " + x + " for p = " + p);
 }
下面的after 通知在匿名切点捕捉到连接点后且程序抛处异常的情况下运行。
 after() throwing(Exception e): target(Point) && call(void setX(int)) {
      System.out.println(e);
 }
around 通知可以取代被捕捉的连接点而执行它自己定义的逻辑,程序原有的逻辑可以通过调用一个特定的方法proceed 执行。
void around(Point p, int x): target(p)
                          && args(x)
                          && call(void setX(int)) {
    if (p.assertX(x)) proceed(p, x);
    p.releaseResources();
}
 
类型间声明 (Inter-type declarations)
       方面能够声明属于其他类型的成员(字段、方法和构造子)。这些被称为类型间成员。方面也能够声明实现新接口或扩展一个新类的其他类型。这里有一些这样的声明的例子。
 
下述声明每个Server 对象有一个名为disabled 的boolean 类型字段,其初始值为false :
       private boolean Server.disabled=false;
这里声明了一个私有的字段,只有这个方面能够访问这个字段。就算是Server 对象本身有另一个私有字段disabled (在Server 内或其他方面里定义)也不会产生名字冲突,因为对于disabled 引用没有二义性。
 
下面代码段声明每个Point 对象有一个名为getX 的方法,它返回各自x 变量的值:
       public int Point.getX(){ return this.x;}
在方法内部,this 就是当前执行的Point 对象。因为方法声明为公共方法,所以任何代码都能调用它,但是如果有另一个Point.getX() 声明,那么就会产生编译期的冲突。
 
下面的公有声明定义Point 对象的一个构造函数,它有两个整型参数:
       public Point.new(int x,int y){       this.x=x;this.y=y;     }
 
下面是一个公有字段声明:
       public int Point.x=0;
它为 Point 对象声明了一个 x 公有字段并初始化为 0 ,因为字段是公有的,在任何地方都可以访问它,所以如果还有另一个 x 字段,则会产生冲突。
 
下面声明了 Point 类实现的接口 Comparable
       declare parents : Point implement Comparable;
当然,除非 Point 类实现了接口的方法,否则会有错误。
 
下面则为 Point 类声明了其扩展的类 GeometricObject
       declare parents : Point extends GeometricObject;
 
一个方面可以有多个类型间声明。例如下面的声明。
       Public String Point.name;
       Public void Point.setName(String name){       this.name=name; }
类型间成员仅仅能够有一个目标类型,但是通常你可能想要在多个类型上声明相同的成员。这可以通过联合使用类型间成员和一个私有接口实现。
 aspect A {
    private interface HasName {}
    declare parents: (Point || Line || Square) implements HasName;
 
    private String HasName.name;
    public String HasName.getName() { return name; }
 }
这里声明了一个 HasName 接口,并声明 Point 、 Line 或 Square 都实现这个接口。而且为接口声明了私有字段 name 和公有方法 getName 。
 
类型间变量的作用域
       AspectJ 允许私有、包保护(缺省)以及公有的类型间声明。私有意味着与 aspect 有私有关系,而与目标对象无关(即目标对象不知道变量或方法的存在)。因此,如果一个方面作出一个字段的私有类型间声明
       Private int Foo.x;
那么方面中的代码可以访问 Foo 的 x 字段,其他类或方面都不行。类似地,如果一个方面作出一个包保护类型间声明
       int Foo.x;
那么在包中的任何代码都可以访问它,包外的代码无权访问。
 
举例: PointAssertions
这个例子包括一个类和一个方面。方面为 Point 声明了私有的 assertion 方法 assertX 和 assertY 。利用这两个断言方法方面对 setX 和 setY 方法的调用提供了保护。断言方法声明为私有是因为没有其他地方需要用到它们,只有方面内部可以使用这些方法。
 class Point {
      int x, y;
      public void setX(int x) { this.x = x; }
      public void setY(int y) { this.y = y; }
 
      public static void main(String[] args) {
          Point p = new Point();
          p.setX(3);
p.setY(333);// 非法的 Y 值
      }
 }
 
 aspect PointAssertions {
           // 如果 X 或 Y 的值不在 0 到 100 之间,则视为非法。
      private boolean Point.assertX(int x) {
          return (x <= 100 && x >= 0);
      }
      private boolean Point.assertY(int y) {
          return (y <= 100 && y >= 0);
      }
      before(Point p, int x): target(p) && args(x) && call(void setX(int)) {
          if (!p.assertX(x)) {      // 若非法输入 X ,则输出提示信息
              System.out.println("Illegal value for x"); return;
          }
      }
      before(Point p, int y): target(p) && args(y) && call(void setY(int)) {
          if (!p.assertY(y)) {      // 若非法输入 Y ,则输出提示信息
              System.out.println("Illegal value for y"); return;
          }
      }
 }
 
thisJoinPoint
       AspectJ 提供了一个特别的引用变量, thisJoinPoint ,它包含了当前连接点处的相关信息并可以被通知使用。 ThisJoinPoint 变量仅仅可以在通知环境中被使用,就象 this 仅能用于非静态方法和构造函数环境中一样。在通知中, thisJoinPoint 是 org.aspectj.lang.JoinPoint 类型的变量。使用它的一个简单作用是直接输出它。和其他 Java 对象一样, thisJoinPoint 有一个 toString() 方法简化了格式化的输出:
 class TraceNonStaticMethods {
      before(Point p): target(p) && call(* *(..)) {
          System.out.println("Entering " + thisJoinPoint + " in " + p);
      }
 }
thisJoinPoint 可以被用来访问静态和动态信息,比如说参数等:
       thisJoinPoint.getArgs();
另外,它持有一个包括所有静态信息的对象,可以通过以下方法得到该对象的引用:
       thisJoinPoint.getStaticPart();
如果你仅需要关于连接点处的静态信息,你可能访问连接点的静态部分直接使用变量 thisJoinPointStaticPart 。使用它将避免运行时直接使用 thisJoinPoint 创建连接点对象。
 
通常情况下
   thisJoinPointStaticPart == thisJoinPoint.getStaticPart()
 
   thisJoinPoint.getKind() == thisJoinPointStaticPart.getKind()
   thisJoinPoint.getSignature() == thisJoinPointStaticPart.getSignature()
   thisJoinPoint.getSourceLocation() == thisJoinPointStaticPart.getSourceLocation()
还有一个相关变量: thisEnclosingJoinPointStaticPart 。它与 thisJoinPointStaticPart 类似,使用它可以打印调用者的位置,例如
   before() : execution (* *(..)) {
     System.err.println(thisEnclosingJoinPointStaticPart.getSourceLocation())
   }
 
导读
本系列下一章将使用 AspectJ 实现一些具体的例子,以便读者可以加强对 AspectJ 的理解并熟悉各种语法。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值