跟我学AspectJ(四)

原创 2003年08月29日 07:32:00
 

第二章          AspectJ语言<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com: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对象有一个名为disabledboolean类型字段,其初始值为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接口,并声明PointLineSquare都实现这个接口。而且为接口声明了私有字段name和公有方法getName

 

类型间变量的作用域

       AspectJ允许私有、包保护(缺省)以及公有的类型间声明。私有意味着与aspect有私有关系,而与目标对象无关(即目标对象不知道变量或方法的存在)。因此,如果一个方面作出一个字段的私有类型间声明

       Private int Foo.x;

那么方面中的代码可以访问Foox字段,其他类或方面都不行。类似地,如果一个方面作出一个包保护类型间声明

       int Foo.x;

那么在包中的任何代码都可以访问它,包外的代码无权访问。

 

举例:PointAssertions

这个例子包括一个类和一个方面。方面为Point声明了私有的assertion方法assertXassertY。利用这两个断言方法方面对setXsetY方法的调用提供了保护。断言方法声明为私有是因为没有其他地方需要用到它们,只有方面内部可以使用这些方法。

  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 {

           //如果XY的值不在0100之间,则视为非法。

      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仅能用于非静态方法和构造函数环境中一样。在通知中,thisJoinPointorg.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的理解并熟悉各种语法。

更多信息

       1AspectJ安装和配置指南

       2跟我学AspectJ(一)

 

如果需要转贴请写名作者和出处。

跟我学aspectj之三 ----- Hello World

一、创建项目     我们将project命名为:aspectjDemo。然后我们新建2个package:com.aspectj.demo.aspect  和 com.aspectj.demo.t...
  • zl3450341
  • zl3450341
  • 2012年06月18日 17:07
  • 13280

跟我学aspectj之四 ----- pointcut基础语法

一、aspect的定义    运行完HelloWorld以后,我们来看下aspect的基础语法: 1、定义一个切面: 关键字aspect。 这定义Java类的语法类似。 2、定义pointc...
  • zl3450341
  • zl3450341
  • 2012年06月18日 17:09
  • 13147

跟我学aspectj之六 ----- 插曲

其实,写这样的文章不太好写, 因为都是牵一发而动全身。介绍pointcut,的时候必要涉及到语法,也会涉及advice,以及一些其他的语法。    所以,如果大家在看博客的过程中,如果有疑问...
  • zl3450341
  • zl3450341
  • 2012年06月18日 17:10
  • 6728

跟我学aspectj之二 ----- 搭建开发环境

一、下载Aspectj以及AJDT     上一章已经列出了他的官方网站,自己上去download吧。AJDT是一个eclipse插件,开发aspectj必装,他可以提供语法检查,以及编译。这里要说...
  • zl3450341
  • zl3450341
  • 2012年06月18日 17:07
  • 18905

跟我学aspectj之七 ----- call,execution,within,withincode

本节开始,我们将详细介绍pointcut的语法 一、call和execution    语法结构:execution([修饰符] 返回值类型 方法名(参数) [异常模式])  蓝色表示可选部分...
  • zl3450341
  • zl3450341
  • 2012年06月18日 17:10
  • 12287

跟我学AspectJ(一)

跟我学AspectJ(一) 编者的话       关于AspectJ的开发资料好象目前还只有英文版的,而且还不是很多,这对于有兴趣学习AOP而英语不是很好的开发人员来是一件很苦闷的事情,所以我决定总结...
  • starchu1981
  • starchu1981
  • 2003年07月22日 07:58
  • 17270

跟我学AspectJ

跟我学AspectJ
  • zlllxl2002
  • zlllxl2002
  • 2015年02月27日 17:03
  • 199

跟我学AspectJ(五)

第三章         AspectJ实例 使用方面的Tracing程序       写一个具有跟踪能力的类是很简单的事情:一组方法,一个控制其开或关的布尔变量,一种可选的输出流,可能还有一些格式化...
  • starchu1981
  • starchu1981
  • 2003年10月27日 02:12
  • 2150

跟我学aspectj之一 ----- 简介

一、为什么写这个系列的博客        Aspectj一个易用的、功能强大的aop编程语言。其官网地址是:http://www.eclipse.org/aspectj/,目前最新版本为:1.7...
  • highway61revisited
  • highway61revisited
  • 2015年05月31日 09:00
  • 123

跟我学AspectJ(二)

跟我学AspectJ(二) 本文继续前篇的内容,将介绍AspectJ的应用范围以及AspectJ的部分基本语言。AspectJ应用范围       如前所述,AspectJ可以用于应用开发的不同阶段。...
  • starchu1981
  • starchu1981
  • 2003年07月27日 11:26
  • 3096
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:跟我学AspectJ(四)
举报原因:
原因补充:

(最多只允许输入30个字)