Spring切面由切点和通知组成。Spring AOP是基于代理的,包括JDK动态代理或者CGLIB动态代理,只支持方法级别的连接点,因此Spring AspectJ风格切点表达式仅仅是AspectJ的子集。表达式之间可以用&&、||、!表示与或非、如果是在XML中配置,那么需要用and、or、not代替&&、||、!。注意,切点的定义如果只到子类,那么父类的方法无法被拦截。
@Before
@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {
// ...
}
@Before("execution(* com.xyz.myapp.dao.*.*(..))")
public void doAccessCheck() {
// ...
}
@AfterReturning
@AfterReturning("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {
// ...
}
如果想要将方法返回的参数传递给通知方法,可以这么配置
@AfterReturning(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
returning="retVal")
public void doAccessCheck(Object retVal) {
// ...
}
returning="retVal"必须和通知方法doAccessCheck里的参数名一样,Object retVal表示可以接收任何类型的返回值。
@AfterThrowing
@AfterThrowing(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
throwing="ex")
public void doRecoveryActions(DataAccessException ex) {
// ...
}
throwing="ex"必须和通知方法doRecoveryActions里的参数名一样,DataAccessException ex表示可以接收DataAccessException类型的异常。
@After
@After("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doReleaseLock() {
// ...
}
@Around
@Around("com.xyz.myapp.SystemArchitecture.businessService()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}
execution
匹配方法,这是最为常用的表达式。格式:execution(访问修饰符-可选 返回类型 方法所属类型-可选 方法名(方法参数) 抛出异常)
返回类型可以用*代表任意类型。
方法所属类型是类的完全限定名,可以用*匹配任意字符,除了.,因此*无法匹配子包或者内部类,..表示一串以.开始和结束的字符串,因此可以用来匹配子包和内部类。
方法名可以用*匹配任意字符。
方法参数可以用..表示任意数量任意类型的参数,*可以代表一个任意类型的参数,比如(*,String),表示第一个参数类型任意,第二个参数是String类型。
execution(public * *(..)):任意public方法
execution(* set*(..)):任意方法名以set开头的方法
execution(* com.xyz.service.AccountService.*(..)):com.xyz.service.AccountService类中的任意方法
execution(* com.xyz.service.*.*(..)):com.xyz.service包中的任意类型的任意方法,不包括子包和内部类
execution(* com.xyz.service..*.*(..)):com.xyz.service包中的任意类型的任意方法,包括子包和内部类
within
匹配某些类型中的所有方法。
within(com.xyz.service.*):com.xyz.service包中的任意类型的所有方法,不包括子包和内部类
within(com.xyz.service..*)::com.xyz.service包中的任意类型的所有方法,不包括子包和内部类
@within
匹配某些类型中的所有方法,这些类型具有指定的注解。
@within(org.springframework.transaction.annotation.Transactional):具有@Transactional注解的类中的所有方法。
this
匹配代理类是某个类型的实例。
this(com.xyz.service.AccountService):代理类是com.xyz.service.AccountService的实例(继承类或者实现接口)
target
匹配某个类型中的所有方法。
target(com.xyz.service.AccountService):com.xyz.service.AccountService中的所有方法。
@target
匹配某个类型中的某些方法,这些方法具有指定类型的注解。
@target(org.springframework.transaction.annotation.Transactional):目标类中具有@Transactional 注解的方法。
args
匹配运行时传递给方法的参数,参数具有指定的数量和类型。
args(java.io.Serializable):表示运行时传递给方法的只有一个参数,且参数是Serializable类型。和execution(* *(java.io.Serializable))不一样,后者表示代码中声明的方法参数类型是Serializable。
@Pointcut("com.xyz.myapp.SystemArchitecture.dataAccessOperation() && args(account,..)")
private void accountDataAccessOperation(Account account) {}
@Before("accountDataAccessOperation(account)")
public void validateAccount(Account account) {
// ...
}
上面的例子是args另外一种用法,向通知方法传参。args(account,..)表示至少有一个参数,且参数的类型是Account,参数值会被传递给通知方法中的account。
@args
匹配运行时传递给方法的参数,参数的类型要具有指定类型的注解。
@args(com.xyz.security.Classified):表示运行时传递给方法的只有一个参数,且参数具有@Classified注解。
@annotation
匹配方法,这个方法要具有指定类型的注解。
@annotation(org.springframework.transaction.annotation.Transactional):目标方法具有@Transactional 注解。