发布日期:2019-08-12 11:00:55

官方文档<<The AspectJTM Programming Guide>>:  https://www.eclipse.org/aspectj/doc/released/progguide/index.html

 

简介:

AspectJ 通过将联接点(join points)的概念叠加到现有的 Java 语义上,并将一些新的程序元素添加到 Java,从而扩展了 Java:

连接点(join points)是程序执行中定义的点。其中包括方法和构造函数调用、字段访问以及下面介绍的其他方法。

切点(PointCut)选取连接点,并在这些连接点的执行上下文中暴露一些值。有几个原始切点指定符(primitive pointcut designators),其他可以由切入点声明命名和定义(pointcut declaration)。

一条建议(Advice)是在切入点中的每个连接点执行的代码。建议(Advice)可以访问切入点(PointCut)所暴露的值。建议(Advice)可以定义在(PointCut 声明)之前、之后和周围执行。

类型间声明(Inter-Type Declation)构成 AspectJ 的静态横切功能,即:通过使用新字段、构造函数或方法添加或扩展接口和类来更改程序的类型结构的代码。某些类型间声明Inter-Type Declation)通过常规方法、字段和构造函数声明的扩展定义,其他声明则使用新的声明关键字进行。

方面(Aspect)是封装切入点、建议和静态横切特征的横切类型。按类型,我们指的是Java的概念:一个模块化的代码单元,具有定义良好的接口,可以在编译时进行推理。方面由方面(aspect)声明定义。

 

Join Point: 

虽然方面(Aspect)定义了横切(Crosscut)的类型,但 AspectJ 系统不允许完全任意横切。相反,方面定义在程序执行中跨越原则点的类型。这些原则点称为联接点。

连接点是程序执行中定义良好的点。AspectJ 定义的连接点有表中的点:

非正式地,当前执行的对象(Current Object)是此表达式将在连接点选取的对象。目标对象(Target Object)是连接点将控制或注意力转移到该位置的位置。参数(Arguments)是为转移控制或注意力而传递的值。

 

 

Pointcuts: https://www.eclipse.org/aspectj/doc/released/progguide/semantics-pointcuts.html 

切入点是一个程序元素,用于选取连接点并从这些连接点的执行上下文中公开数据。切入点主要通过建议(advice)使用。它们可以由布尔运算符组成,以构建其他切入点。

学习Pointcuts主要学习: 1)PointCut的定义 2)Context expose(上下文数据如何披露) 3)原始的pointcuts 4) Signatures 5) Matching

语言提供的原始切入点和组合器是:

call(MethodPattern)
Picks out each method call join point whose signature matches MethodPattern.
execution(MethodPattern)
Picks out each method execution join point whose signature matches MethodPattern.
get(FieldPattern)
Picks out each field reference join point whose signature matches FieldPattern. [Note that references to constant fields (static final fields bound to a constant string object or primitive value) are not join points, since Java requires them to be inlined.]
set(FieldPattern)
Picks out each field set join point whose signature matches FieldPattern. [Note that the initializations of constant fields (static final fields where the initializer is a constant string object or primitive value) are not join points, since Java requires their references to be inlined.]
call(ConstructorPattern)
Picks out each constructor call join point whose signature matches ConstructorPattern.
execution(ConstructorPattern)
Picks out each constructor execution join point whose signature matches ConstructorPattern.
initialization(ConstructorPattern)
Picks out each object initialization join point whose signature matches ConstructorPattern.
preinitialization(ConstructorPattern)
Picks out each object pre-initialization join point whose signature matches ConstructorPattern.
staticinitialization(TypePattern)
Picks out each static initializer execution join point whose signature matches TypePattern.
handler(TypePattern)
Picks out each exception handler join point whose signature matches TypePattern.
adviceexecution()
Picks out all advice execution join points.
within(TypePattern)
Picks out each join point where the executing code is defined in a type matched by TypePattern.
withincode(MethodPattern)
Picks out each join point where the executing code is defined in a method whose signature matches MethodPattern.
withincode(ConstructorPattern)
Picks out each join point where the executing code is defined in a constructor whose signature matches ConstructorPattern.
cflow(Pointcut)
Picks out each join point in the control flow of any join point P picked out by Pointcut, including P itself.
cflowbelow(Pointcut)
Picks out each join point in the control flow of any join point P picked out by Pointcut, but not P itself.
this(Type or Id)
Picks out each join point where the currently executing object (the object bound to this) is an instance of Type, or of the type of the identifier Id (which must be bound in the enclosing advice or pointcut definition). Will not match any join points from static contexts.
target(Type or Id)
Picks out each join point where the target object (the object on which a call or field operation is applied to) is an instance of Type, or of the type of the identifier Id (which must be bound in the enclosing advice or pointcut definition). Will not match any calls, gets, or sets of static members.
args(Type or Id, ...)
Picks out each join point where the arguments are instances of the appropriate type (or type of the identifier if using that form). A null argument is matched iff the static type of the argument (declared parameter type or field type) is the same as, or a subtype of, the specified args type.
PointcutId(TypePattern or Id, ...)
Picks out each join point that is picked out by the user-defined pointcut designator named by PointcutId.
if(BooleanExpression)
Picks out each join point where the boolean expression evaluates to true. The boolean expression used can only access static members, parameters exposed by the enclosing pointcut or advice, and thisJoinPoint forms. In particular, it cannot call non-static methods on the aspect or use return values or exceptions exposed by after advice.
! Pointcut
Picks out each join point that is not picked out by Pointcut.
Pointcut0 && Pointcut1
Picks out each join points that is picked out by both Pointcut0 and Pointcut1.
Pointcut0 || Pointcut1
Picks out each join point that is picked out by either pointcuts. Pointcut0 or Pointcut1.
( Pointcut )
Picks out each join points picked out by Pointcut.

Pattern摘要

MethodPattern = 
  [ModifiersPattern] TypePattern 
        [TypePattern . ] IdPattern (TypePattern | ".." , ... ) 
        [ throws ThrowsPattern ]
ConstructorPattern = 
  [ModifiersPattern ] 
        [TypePattern . ] new (TypePattern | ".." , ...) 
        [ throws ThrowsPattern ]
FieldPattern = 
  [ModifiersPattern] TypePattern [TypePattern . ] IdPattern
ThrowsPattern = 
  [ ! ] TypePattern , ...
TypePattern = 
    IdPattern [ + ] [ [] ... ]
    | ! TypePattern
    | TypePattern && TypePattern
    | TypePattern || TypePattern
    | ( TypePattern )  
IdPattern =
  Sequence of characters, possibly with special * and .. wildcards
ModifiersPattern =
  [ ! ] JavaModifier  ...

 

Advice: https://www.eclipse.org/aspectj/doc/released/progguide/semantics-advice.html

 

Each piece of advice is of the form

[ strictfp ] AdviceSpec [ throws TypeList ] : Pointcut { Body }
where AdviceSpec is one of
before( Formals )
after( Formals ) returning [ ( Formal ) ]
after( Formals ) throwing [ ( Formal ) ]
after( Formals )
Type around( Formals )
and where Formal refers to a variable binding like those used for method parameters, of the form Type Variable-Name, and Formals refers to a comma-delimited list of Formal.

 

Inter-type: https://www.eclipse.org/aspectj/doc/released/progguide/language-interType.html

Aspects can declare members (fields, methods, and constructors) that are owned by other types. These are called inter-type members. Aspects can also declare that other types implement new interfaces or extend a new class.

AspectJ allows the declaration of members by aspects that are associated with other types.

An inter-type method declaration looks like

 [ Modifiers ] Type OnType . Id(Formals) [ ThrowsClause ] { Body }
abstract [ Modifiers ] Type OnType . Id(Formals) [ ThrowsClause ] ;
The effect of such a declaration is to make OnType support the new method. Even if OnType is an interface. Even if the method is neither public nor abstract. So the following is legal AspectJ code:
An inter-type constructor declaration looks like

 [ Modifiers ] OnType . new ( Formals ) [ ThrowsClause ] { Body }
An inter-type field declaration looks like one of

 [ Modifiers ] Type OnType . Id = Expression;
 [ Modifiers ] Type OnType . Id;

举些例子:

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);
      }
  }
1) private boolean Server.disabled = false;

2)public int Point.getX() { return this.x; }

3)public Point.new(int x, int y) { this.x = x; this.y = y; }

4)declare parents: Point implements Comparable;

5)declare parents: Point extends GeometricObject;

6)public String Point.name;
  public void Point.setName(String name) { this.name = name; }

7)aspect A {
    private interface HasName {}
    declare parents: (Point || Line || Square) implements HasName;

    private String HasName.name;
    public  String HasName.getName()  { return name; }
  }

 

Static crosscutting https://www.eclipse.org/aspectj/doc/released/progguide/semantics-declare.html

Advice declarations change the behavior of classes they crosscut, but do not change their static type structure. For crosscutting concerns that do operate over the static structure of type hierarchies, AspectJ provides inter-type member declarations and other declare forms.

除了Inter-type member declarations之外,我们还有其他的decalaration, 比如:1)Warnings and Errors 2)Softened exceptions 3)Advice Precedence 4)Statically determinable pointcuts 5)Extension and Implementation

Extension and Implementation

An aspect may change the inheritance hierarchy of a system by changing the superclass of a type or adding a superinterface onto a type, with the declare parents form.

declare parents: TypePattern extends Type;
declare parents: TypePattern implements TypeList;

例如

aspect A {
      declare parents: SomeClass implements Runnable;
      public void SomeClass.run() { ... }
  }

Warnings and Errors

An aspect may specify that a particular join point should never be reached.

declare error: Pointcut: String;
declare warning: Pointcut: String;
If the compiler determines that a join point in Pointcut could possibly be reached, then it will signal either an error or warning, as declared, using the String for its message.

Softened exceptions

An aspect may specify that a particular kind of exception, if thrown at a join point, should bypass Java's usual static exception checking system and instead be thrown as a org.aspectj.lang.SoftException, which is subtype of RuntimeException and thus does not need to be declared.

declare soft: Type: Pointcut;

Advice Precedence

An aspect may declare a precedence relationship between concrete aspects with the declare precedence form:

declare precedence : TypePatternList ;

Statically determinable pointcuts

Pointcuts that appear inside of declare forms have certain restrictions. Like other pointcuts, these pick out join points, but they do so in a way that is statically determinable.

Consequently, such pointcuts may not include, directly or indirectly (through user-defined pointcut declarations) pointcuts that discriminate based on dynamic (runtime) context. Therefore, such pointcuts may not be defined in terms of

cflow
cflowbelow
this
target
args
if
all of which can discriminate on runtime information.

 

Aspect: https://www.eclipse.org/aspectj/doc/released/progguide/semantics-aspects.html

An aspect is a crosscutting type defined by the aspect declaration.

学习Aspect定义,主要靠考虑1)Aspect Declaration 2) Aspect Extension 3) Aspect instantiation 4) Aspect Privilege

The aspect declaration is similar to the class declaration in that it defines a type and an implementation for that type. It differs in a number of ways:

Aspect implementation can cut across other types

In addition to normal Java class declarations such as methods and fields, aspect declarations can include AspectJ declarations such as advice, pointcuts, and inter-type declarations. Thus, aspects contain implementation declarations that can can cut across other types (including those defined by other aspect declarations).

Aspects are not directly instantiated

Aspects are not directly instantiated with a new expression, with cloning, or with serialization. Aspects may have one constructor definition, but if so it must be of a constructor taking no arguments and throwing no checked exceptions.

Nested aspects must be static

Aspects may be defined either at the package level, or as a static nested aspect -- that is, a static member of a class, interface, or aspect. If it is not at the package level, the aspect must be defined with the static keyword. Local and anonymous aspects are not allowed.
Aspect Extension

To support abstraction and composition of crosscutting concerns, aspects can be extended in much the same way that classes can. Aspect extension adds some new rules, though.

Aspects may extend classes and implement interfaces

An aspect, abstract or concrete, may extend a class and may implement a set of interfaces. Extending a class does not provide the ability to instantiate the aspect with a new expression: The aspect may still only define a null constructor.

Classes may not extend aspects

It is an error for a class to extend or implement an aspect.

Aspects extending aspects

Aspects may extend other aspects, in which case not only are fields and methods inherited but so are pointcuts. However, aspects may only extend abstract aspects. It is an error for a concrete aspect to extend another concrete aspect.

Aspect的初始化

Unlike class expressions, aspects are not instantiated with new expressions. Rather, aspect instances are automatically created to cut across programs. A program can get a reference to an aspect instance using the static method aspectOf(..).

Because advice only runs in the context of an aspect instance, aspect instantiation indirectly controls when advice runs.

The criteria used to determine how an aspect is instantiated is inherited from its parent aspect. If the aspect has no parent aspect, then by default the aspect is a singleton aspect. How an aspect is instantiated controls the form of the aspectOf(..) method defined on the concrete aspect class.
Singleton Aspects

aspect Id { ... }
aspect Id issingleton() { ... }
Per-object aspects

aspect Id perthis(Pointcut) { ... }
aspect Id pertarget(Pointcut) { ... }
Per-control-flow aspects

aspect Id percflow(Pointcut) { ... }
aspect Id percflowbelow(Pointcut) { ... }

Aspect privilege​

privileged aspect Id { ... }

举个例子

 class C {
      private int i = 0;
      void incI(int x) { i = i+x; }
  }
  privileged aspect A {
      static final int MAX = 1000;
      before(int x, C c): call(void C.incI(int)) && target(c) && args(x) {
	  if (c.i+x > MAX) throw new RuntimeException();
      }
  }
In this case, if A had not been declared privileged, the field reference c.i would have resulted in an error signaled by the compiler.

 

发表评论