面向切面编程中切面实例化机制的设计与实现
立即解锁
发布时间: 2025-08-20 00:01:06 阅读量: 1 订阅数: 5 


面向方面软件开发交易I
# 面向切面编程中切面实例化机制的设计与实现
## 1. 关联切面的特性
### 1.1 可变性
关联切面具有可变性,通过将关联切入点与 AspectJ 的抽象机制(如抽象切面和切入点重写)相结合,能描述对称和非对称关系。以 Bit 集成为例,可以定义一个包含抽象切入点的切面以及具有具体切入点的子切面,来指定对称或非对称关系。
### 1.2 简单性
关联切面隐藏了关系的实现细节,使得代码更加简单。例如,图 4 中的 Equality 比图 3 中的更简单,因为图 3 中显式地展示了关系的实现细节(如 `Bit.relations` 字段和 `after` 通知中迭代器的使用)。此外,关联切入点与自由变量的组合避免了通知声明的重复。
## 2. 切面实例的创建与关联
### 2.1 切面声明语法
关联切面使用 `perobjects` 修饰符进行声明,语法如下:
```java
aspect A perobjects(T , ...) { mdecl ... }
```
其中,`A` 是切面的名称,`T` 是要关联的对象类型,`mdecl` 是成员声明,包括构造函数、方法、变量、通知等。
### 2.2 实例化与关联操作
关联切面可以通过执行 `new A(...)` 表达式进行实例化,新创建的切面实例不会关联到任何对象。`perobjects(T1, T2, ..., Tn)` 修饰符会自动在切面 `A` 中定义 `associate` 方法,该方法接受 `n` 个类型为 `T1, ..., Tn` 的对象,并将切面实例关联到这些对象。同时,还会定义 `void A.delete()` 方法,用于撤销关联。
与 AspectJ 中的 per - object 切面不同,关联切面的创建和关联是显式的。当在某些连接点需要为对象创建关联切面时,可以通过定义通知来使这些操作变得非侵入性。
## 3. 切面实例的通知分发
### 3.1 分发语义
从语义上讲,将通知分发给切面实例是通过尝试在所有切面实例的上下文中执行相同的通知来实现的,只有满足切入点的实例才会实际运行通知体。为了选择关联的切面实例,提供了关联切入点原语。
### 3.2 示例说明
以图 5 为例,当执行 `b2.set()` 时,会创建一个调用连接点。对于第二个通知声明,每个切面实例都会测试切入点。由于只有当切面实例以 `b2` 作为第二个参数关联时,切入点才会满足,因此只有 `a1` 会运行通知。
### 3.3 环绕通知的执行步骤
对于环绕通知,执行以下四个步骤:
1. 从所有切面实例中随机选择一个切面实例。
2. 所选切面实例测试并执行通知声明。
3. 当切面实例执行 `proceed` 形式,或者切面实例不匹配通知声明时,选择下一个切面实例并从第二步开始重复。如果切面实例不执行 `proceed` 形式,则继续执行而不运行连接点。
4. 当在第一步或第三步的最后部分没有更多的切面实例时,继续执行连接点。
### 3.4 关联切入点
关联切入点 `associated(v1, ..., vn)` 用于确定切面实例如何与对象关联,其中 `vi` 可以是:
- 由另一个切入点绑定的变量(例如,通过 `target(vi)`)
- 作为通配符的星号(`*`),或自由变量
关联切入点的参数中至少要有一个绑定变量。对于关联到 `<o1, ..., on>` 的切面实例,如果对于任何 `1 ≤ i ≤ n`,`vi` 是星号、自由变量或绑定到 `oi` 的变量,则 `associated(v1, ..., vn)` 切入点的计算结果为 `true`。星号和自由变量允许多个切面实例匹配同一个连接点。
### 3.5 绑定到关联对象
关联切入点可以将变量绑定到关联对象。例如,以下修改后的通知声明:
```java
after(Bit l, Bit r) : call(void Bit.set())
&& target(l) && associated(l,r) {
propagateSet(r);
}
```
与原始通知行为相同,只是在执行通知体时,将 `r` 绑定到第二个参数位置的关联对象。
对于对称关联切面,绑定特性可以给出更简短的定义。例如,以下单个通知声明可以替代图 4 中的前两个通知声明:
```java
after(Bit b,Bit o): call(void Bit.set()) && target(b)
&& (associated(b,o) || associated(o,b)) {
propagateSet(o);
}
```
通过析取运算符组合关联切入点可以识别与目标对象关联的切面实例,而绑定特性将 `o` 绑定到非目标的关联对象。
## 4. 静态通知
关联切面可以声明静态通知,其语义与单例切面中的通知声明类似。当通知声明带有 `static` 修饰符时,切入点匹配和执行只进行一次,无论现有切面实例的数量如何。显然,静态通知声明不能使用关联切入点,其执行上下文是切面类,通知体只能访问静态(或类)变量。
静态通知声明通常用于引导。例如,以下代码中的通知在 `callSomeMethod()` 发生时创建一个 `Equality` 实例:
```java
aspect Equality perobjects(Bit, Bit) {
static after(Bit l, Bit r) : callSomeMethod() && args(l,r) {
new Equality(l,r); // 创建一个切面实例
}
...
}
```
## 5. 查找切面实例的惯用法
### 5.1 避免重复实例化
有时需要检查是否有与特定对象元组关联的切面实例,或者对与特定对象关联的所有切面实例执行某些操作。这些操作可以通过带有关联切入点的通知声明来实现。
例如,为了防止为同一对对象创建多个 `Equality` 切面实例,可以使用以下通知:
```java
aspect Equality perobjects(Bit,Bit) {
...
Equality around(Bit l, Bit r) :
call(Equality.new(Bit,Bit)) && args(l,r)
&& (associated(l,r) || associated(r,l)) {
return this;
}
}
```
当程序执行 `new Equality(b, b')` 时,如果已经有与 `<b, b'>` 或 `<b', b>` 关联的切面实例,则上述通知会返回该实例,而不是创建新实例。
### 5.2 枚举关联实例
枚举与特定对象关联的所有切面实例可以通过一个空的静态方法和通知声明来实现。例如,执行 `Equality.showAll(b)` 可以显示所有与 `b` 关联的切面实例:
```java
aspect Equality perobjects(Bit,Bit) {
...
static void showAll(Bit b) { }
// 空主体
after(Bit b) :
call(void Equality.showAll(Bit)) && args(Bit b)
&& (associated(b,*) || associated(*,b)) {
System.out.println(this);
// this 绑定到关联实
```
0
0
复制全文
相关推荐










