@Pointcut(\
private void tradingOperation() {}就上所示的,从更小的命名组件来构建更加复杂的切入点表达式是一种最佳实践。 当用名字来指定切入点时使用的是常见的Java成员可视性访问规则。 (比如说,你可以在同一类型中访问私有的切入点,在继承关系中访问受保护的切入点,可以在任意地方访问公共切入点。 成员可视性访问规则不影响到切入点的 匹配。
在AspectJ 1.5.1中有一个bug (#140357)有时候可能会导致Spring所使用的AspectJ切入点解析失败, 即使用一个已命名的切入点来引用到另一个同类型的切入点的时候。 在AspectJ的开发中已经解决这个bug,可以在AspectJ的下载页面得到。在1.5.2发布时将会包含这一fix。 如果你遇到了这个问题,你可以去下载AspectJ的开发构建包,并且更新你的 aspectjweaver.jar,这是在AspectJ 1.5.2发布前的临时解决方案。 6.2.3.3. 共享常见的切入点(pointcut)定义
当开发企业级应用的时候,你通常会想要从几个切面来参考模块化的应用和特定操作的集合。 我们推荐定义一个“SystemArchitecture”切面来捕捉常见的切入点表达式。一个典型的切面可能看起来像下面这样:
package com.xyz.someapp;
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class SystemArchitecture {
/**
* A join point is in the web layer if the method is defined
* in a type in the com.xyz.someapp.web package or any sub-package * under that. */
@Pointcut(\ public void inWebLayer() {}
/**
* A join point is in the service layer if the method is defined * in a type in the com.xyz.someapp.service package or any sub-package * under that. */
@Pointcut(\ public void inServiceLayer() {}
/**
* A join point is in the data access layer if the method is defined
* in a type in the com.xyz.someapp.dao package or any sub-package * under that. */
@Pointcut(\ public void inDataAccessLayer() {}
/** * A business service is the execution of any method defined on a service * interface. This definition assumes that interfaces are placed in the
* \sub-packages. *
* If you group service interfaces by functional area (for example, * in packages com.xyz.someapp.abc.service and com.xyz.def.service) then
* the pointcut expression \com.xyz.someapp..service.*.*(..))\ * could be used instead. */
@Pointcut(\ public void businessService() {}
/**
* A data access operation is the execution of any method defined on a
* dao interface. This definition assumes that interfaces are placed in the
* \ */
@Pointcut(\ public void dataAccessOperation() {}
}示例中的切入点定义一个你可以在任何需要切入点表达式的地方可引用的切面。比如,为了使service层事务化,你可以写:
pointcut=\ advice-ref=\
在 Section 6.3, “Schema-based AOP support” 中讨论
和 标签。 在 Chapter 9, 事务管理 中讨论事务标签。
6.2.3.4. 示例
Spring AOP 用户可能会经常使用 execution pointcut designator。执行表达式的格式如下:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)除了返回类型模式,名字模式和参数模式以外,所有的部分都是可选的。 返回类型模式决定了方法的返回类型必须依次匹配一个连接点。 你会使用的最频繁的返回类型模式是 *,它代表了匹配任意的返回类型。 一个全称限定的类型名将只会匹配返回给定类型的方法。名字模式匹配的是方法名。 你可以使用 * 通配符作为所有或者部分命名模式。 参数模式稍微有点复杂:() 匹配了一个不接受任何参数的方法, 而 (..) 匹配了一个接受任意数量参数的方法(零或者更多)。 模式 (*) 匹配了一个接受一个任何类型的参数的方法。 模式 (*,String) 匹配了一个接受两个参数的方法,第一个可以是任意类型,第二个则必须是String类型。 请参见AspectJ编程指南的 Language Semantics 部分。
下面给出一些常见切入点表达式的例子。
任意公共方法的执行:
execution(public * *(..))任何一个以“set”开始的方法的执行:
execution(* set*(..))AccountService 接口的任意方法的执行:
execution(* com.xyz.service.AccountService.*(..))定义在service包里的任意方法的执行:
execution(* com.xyz.service.*.*(..))定义在service包或者子包里的任意方法的执行:
execution(* com.xyz.service..*.*(..))在service包里的任意连接点(在Spring AOP中只是方法执行) :
within(com.xyz.service.*)在service包或者子包里的任意连接点(在Spring AOP中只是方法执行) :
within(com.xyz.service..*)实现了 AccountService 接口的代理对象的任意连接点(在Spring AOP中只是方法执行) :
this(com.xyz.service.AccountService)'this'在binding form中用的更多:- 请常见以下讨论通知的章节中关于如何使得代理对象可以在通知体内访问到的部分。
实现了 AccountService 接口的目标对象的任意连接点(在Spring AOP中只是方法执行) :
target(com.xyz.service.AccountService)'target'在binding form中用的更多:- 请常见以下讨论通知的章节中关于如何使得目标对象可以在通知体内访问到的部分。
任何一个只接受一个参数,且在运行时传入的参数实现了 Serializable 接口的连接点 (在Spring AOP中只是方法执行)
args(java.io.Serializable)'args'在binding form中用的更多:- 请常见以下讨论通知的章节中关于如何使得方法参数可以在通知体内访问到的部分。 请注意在例子中给出的切入点不同于 execution(* *(java.io.Serializable)): args只有在动态运行时候传入参数是可序列化的(Serializable)才匹配,而execution 在传入参数的签名声明的类型实现了 Serializable 接口时候匹配。
有一个 @Transactional 注解的目标对象中的任意连接点(在Spring AOP中只是方法执行)
@target(org.springframework.transaction.annotation.Transactional)'@target' 也可以在binding form中使用:请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。
任何一个目标对象声明的类型有一个 @Transactional 注解的连接点(在Spring AOP中只是方法执行)
@within(org.springframework.transaction.annotation.Transactional)'@within'也可以在binding form中使用:- 请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。
任何一个执行的方法有一个 @Transactional annotation的连接点(在Spring AOP中只是方法执行)
@annotation(org.springframework.transaction.annotation.Transactional)'@annotation' 也可以在binding form中使用:- 请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。
任何一个接受一个参数,并且传入的参数在运行时的类型实现了 @Classified annotation的连接点(在Spring AOP中只是方法执行)
@args(com.xyz.security.Classified)'@args'也可以在binding form中使用:- 请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。
6.2.4. 声明通知
通知是跟一个切入点表达式关联起来的,并且在切入点匹配的方法执行之前或者之后或者之前和之后运行。 切入点表达式可能是指向已命名的切入点的简单引用或者是一个已经声明过的切入点表达式。
6.2.4.1. 前置通知(Before advice)
一个切面里使用 @Before 注解声明前置通知:
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before(\ public void doAccessCheck() { // ... }
}如果使用一个in-place 的切入点表达式,我们可以把上面的例子换个写法:
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before(\ public void doAccessCheck() { // ... }
}6.2.4.2. 返回后通知(After returning advice)
返回后通知通常在一个匹配的方法返回的时候执行。使用 @AfterReturning 注解来声明:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {