连接点模型
在系统中并不是所有的连接点都可以被使用,而系统中可以被切点所选择的连接点称为暴露(exposed)连接点。AspectJ仅允许你使用系统所有连接点的一个子集,例如你不能暴露一个循环连接点,因为那样你就可以非常容易将一个for循环改变成一个while循环,而这两个循环的功能是相同的,仅仅是使用习惯的不同而已。而且为该连接点申明的通知仅仅只能使用在该连接点上。AspectJ中可以暴露的连接点包括:方法的调用和执行、对象的实例化、字段的访问、以及异常的处理。
所有的连接点都有一个上下文与之关联。例如一个方法调用的连接点的上下文包括方法的调用对象、目标对象、方法的参数列表。切点能够捕获这些连接点的上下文,并且能在通知体中使用之。
暴露连接点种类
方法连接点(Method join points)
AspectJ为每种方法暴露两种类型的连接点:执行和调用连接点。执行连接点就是方法体本身,而调用连接点是在程序的另一部分,一般位于调用该方法的那句代码的位置。
方法的执行连接点包括了方法中的所有代码,如:
public class Account {
...
public void debit(float amount)
throws InsufficientBalanceException {
if (_balance < amount) {
throw new InsufficientBalanceException( <
"Total balance not sufficient"); < debit方法的
} else { < 执行连接点
_balance -= amount; <
} <
} <
}
方法的调用连接点位于该方法被调用的位置,如:
Account account = ...;
account.debit(100); <- debit方法的调用连接点
注意其中方法的参数部分并不属于连接的部分。
构造连接点(Constructor join points)
位于构造函数中的暴露连接点和多数的方法连接点是一样的,
除了它包含了创建一个对象的执行逻辑
。构造连接点的执行连接点就是构造函数本身,而调用连接点则位于创建对象逻辑的部分。一个典型的使用方法是影响对象的创建,例如当创建一个对象时,你可以使用构造连接点来绕过创建(不创建新的对象),而使用以前已经创建的对象。
字段访问连接点(Field access join points)
字段访问连接点捕获对一个类的实例或类成员进行读写的访问操作。注意这里只有访问类的数据成员的连接点才会暴露,就是说方法内的局部变量的访问是不被暴露的。
在通知中使用这些连接点的典型用法是在使用对象前确信该对象被正确初始化。
public class Account {
int _accountNumber;
...
public String toString() {
return "Account: "
+ _accountNumber <- 读访问连接点
+ ...
}
...
}
public class Account {
int _accountNumber;
public Account(int accountNumber) {
_accountNumber = accountNumber; <- 写访问连接点
}
...
}
异常处理执行连接点(Exception handler execution join points)
异常处理执行连接点描绘了一个异常类型的处理块。
try {
account.debit(amount);
} catch (InsufficientBalanceException ex) {
postMessage(ex); < 异常
OverdraftManager.applyOverdraftProtection(account, < 处理
amount); < 连接点
}
类初始化连接点(Class initialization join points)
类初始化连接点描绘了一个类的装载,包括静态部分的初始化。该连接点用于类等级的横切。
public class Account {
...
static {
try { <
System.loadLibrary("accounting"); < 类初始化
} catch (UnsatisfiedLinkError error) { < 连接点
... deal with the error <
} <
}
...
}
对象初始化连接点(Object initialization join points)
对象初始化连接点捕获一个对象的初始化,从该对象的父对象的构造函数返回开始,直到第一次调用该对象的构造函数结束位置。
public class SavingsAccount extends Account {
...
public SavingsAccount(int accountNumber, boolean isOverdraft) {
super(accountNumber);
_isOverdraft = isOverdraft; <- 对象初始化连接点
}
public SavingsAccount(int accountNumber) {
this(accountNumber, false); <- 对象初始化连接点
}
...
}
对象预初始化连接点(Object pre-initialization join points)
public class SavingsAccount extends Account {
...
public SavingsAccount(int accountNumber) {
super(accountNumber,
AccountManager.internalId(accountNumber) <- 对象预初始化连接点
);
_type = AccountConstants.SAVINGS;
}
...
}
通知执行连接点(Advice execution join points)
通知执行连接点包括了系统中所有通知的执行体。
public aspect MannersAspect {
before() : deliverMessage() {
System.out.print("Hello! "); < 通知执行连接点
}
}
public aspect LoggingAspect {
after() : loggedOperations() {
... <
_logger.log(...); < 通知执行连接点
... <
}
}