深入理解AspectJ切入点设计器
立即解锁
发布时间: 2025-08-19 00:42:42 阅读量: 1 订阅数: 3 


精通AspectJ:Java面向切面编程指南
### 深入理解 AspectJ 切入点设计器
在 Java 开发中,AspectJ 为我们提供了强大的 AOP(面向切面编程)功能,其中切入点设计器是实现 AOP 的关键部分。下面将详细介绍 AspectJ 中各种切入点设计器的使用方法和特点。
#### 设计器参数类型
设计器中的“参数”可以是连接点签名、连接点类类型或另一个切入点。连接点签名通常代表方法、类构造函数或类型的签名,可能包含多种通配符,在构造函数连接点的情况下,签名会包含 `new()` 调用。连接点类类型的参数是应用程序中类的名称,类类型也可以使用通配符。
TypePattern 通常是应用程序中的类,可带或不带通配符,例如 `DVD` 或 `PRODUCT+`。
#### 设计器快速参考
以下是常见设计器的快速参考:
| 设计器 | 描述 |
| --- | --- |
| execution | 匹配方法或构造函数的执行 |
| call | 匹配对方法或构造函数的调用 |
| initialization | 匹配类的第一个构造函数的执行 |
| handler | 匹配异常处理 |
| get | 匹配对类属性的引用 |
| set | 匹配对类属性的赋值 |
| this | 返回与特定连接点关联的对象或使用类类型限制连接点的范围 |
| target | 返回连接点的目标对象或限制连接点的范围 |
| args | 暴露连接点的参数或限制切入点的范围 |
| cflow | 返回另一个连接点执行流中的连接点 |
| cflowbelow | 返回另一个连接点执行流中的连接点,但不包括当前连接点 |
| staticinitialization | 匹配类的静态初始化代码的执行 |
| withincode | 匹配方法或构造函数内的连接点 |
| within | 匹配特定类型内的连接点 |
| if | 允许动态条件成为切入点的一部分 |
| adviceexecution | 匹配通知连接点 |
| preinitialization | 匹配预初始化连接点 |
#### 使用逻辑运算符创建设计器组合
所有设计器都可以使用标准逻辑运算符进行组合:
- `&& (and)`:当运算符的两个参数都为真时匹配。
- `|| (or)`:当运算符的一个或多个参数为真时匹配。
- `! (not)`:匹配未被定义切入点匹配的所有连接点。
使用逻辑运算符组合设计器时,要注意正确排列参数顺序。如果对系统如何计算逻辑组合有疑问,可以使用括号对组合进行分组以获得期望的结果。
#### 组合切入点
编写切入点时可以将它们组合起来,例如:
```java
pointcut setLoc() :
call(public void DVD.setLocation(..));
pointcut setStat() :
call(public void DVD.setStats(String, int));
pointcut localSetLoc() :
setLoc() && cflow(setStat());
before() : localSetLoc() {
System.out.println(thisJoinPoint.toLongString());
}
```
第三个切入点定义包含了之前定义的 `setLoc()` 和 `setStat()` 切入点,使切入点的编写更加简洁易读。
#### 方法相关切入点
`execution`、`call` 和 `initialization` 这三个设计器属于方法相关切入点,用于在 Java 类的方法或构造函数被调用和/或执行时匹配切入点。
##### execution
`execution` 设计器用于匹配主应用程序中类的方法或构造函数上定义的连接点。当你关注方法或构造函数的实际执行时使用该设计器,格式为 `execution(join point signature)`。
例如:
```java
pointcut Location() :
execution(public void setLocation(String));
```
此切入点会匹配主应用程序中所有具有 `setLocation(String)` 方法的对象,只有当连接点定义的方法开始执行时才会匹配。执行的定义是从方法的第一条语句执行前开始,到方法或构造函数的最后一条语句执行后结束。
`execution` 设计器也适用于类构造函数,例如:
```java
pointcut DVDConstruct : execution (public DVD.new(..));
```
当任何 `DVD` 对象的默认构造函数执行时,此代码将匹配切入点。
考虑以下示例:
```java
pointcut DVDConstruct() : execution (public DVD.new(..));
before() : DVDConstruct() {
System.out.println(thisJoinPoint.toLongString());
}
```
输出可能如下:
```
execution(public DVD(java.lang.String))
store 1
```
这表明 AspectJ 运行时系统确定 `DVD` 类中的一个构造函数正在执行,此时切入点通知代码执行并显示匹配连接点的全名。
##### call
`call` 设计器也用于匹配方法或构造函数上定义的连接点。当你关注方法或构造函数的实际调用而不是连接点内代码的执行时使用该设计器,格式为 `call(join point signature)`。
例如:
```java
pointcut DVDGetLoc() :
call(public String DVD.getLocation());
```
此切入点在任何 `DVD` 对象的 `getLocation()` 方法被调用时匹配,切入点的范围是执行实际调用的对象或静态方法。
结合建议代码如下:
```java
pointcut DVDGetLoc() : call(public String DVD.getLocation());
before() : DVDGetLoc() {
System.out.println(thisJoinPoint.toLongString());
}
```
输出可能为:
```
call(public java.lang.String DVD.getLocation())
store 1
```
下面的代码同时使用了 `execution`、`call` 和 `this` 设计器:
```java
pointcut Stats(Object obj) :
execution(public void DVD.setStats(..)) &&
this(obj);
pointcut Stats2(Object obj);
call(public void DVD.setStats(..)) &&
this(obj);
pointcut allStats(Object obj) :
Stats(obj) ||
Stats2(obj);
before(Object obj) : DVDGetLoc(obj) {
System.out.println(thisJoinPoint.toLongString());
if (obj instanceof DVD)
System.out.println("DVD object");
else if (obj instanceof Boxset)
System.out.println("Boxset object");
else
System.out.println("Unknown object");
}
```
执行时的输出可能为:
```
call(public void DVD.setStats(java.lang.String, int))
```
0
0
复制全文