在前一章讲解了注解方式的定义的AOP基本使用方式,在本节讲解下AOP的@PointCut表达式的多种写法(本质还是AspectJ表达式语法)。
Supported Pointcut Designators
以下是Spring所支持的表达式标识符(AspectJ标识符的子集)。Pointcut Designator简称PCD。
-
execution: For matching method execution join points. This is the primary pointcut designator to use when working with Spring AOP.
-
within: Limits matching to join points within certain types (the execution of a method declared within a matching type when using Spring AOP).
-
this: Limits matching to join points (the execution of methods when using Spring AOP) where the bean reference (Spring AOP proxy) is an instance of the given type.
-
target: Limits matching to join points (the execution of methods when using Spring AOP) where the target object (application object being proxied) is an instance of the given type.
-
args: Limits matching to join points (the execution of methods when using Spring AOP) where the arguments are instances of the given types.
-
@target: Limits matching to join points (the execution of methods when using Spring AOP) where the class of the executing object has an annotation of the given type.
-
@args: Limits matching to join points (the execution of methods when using Spring AOP) where the runtime type of the actual arguments passed have annotations of the given types.
-
@within: Limits matching to join points within types that have the given annotation (the execution of methods declared in types with the given annotation when using Spring AOP).
-
@annotation: Limits matching to join points where the subject of the join point (the method being executed in Spring AOP) has the given annotation.
Spring AOP还额外支持的PCD 为bean标识符,可以通过指定bean name来过滤bean:
bean(idOrNameOfBean)
Combining Pointcut Expressions
PointCut表达式可以通过&&, || 和 ! 运算符组合。
tradingOperation为anyPublicOperation和inTrading表达式组合后的结果,tradingOperation的过滤结果等于anyPublicOperation与inTrading过滤结果的交集。这样我们在指定切点表达式时,可以通过组合的方式复用过滤条件,所以切点的条件表达式定义的越细越好,从而使其他切点表达式定义可以直接复用。
@Pointcut("execution(public * *(..))")
private void anyPublicOperation() {}
@Pointcut("within(com.xyz.someapp.trading..*)")
private void inTrading() {}
@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation() {}
Sharing Common Pointcut Definitions
可以通过划分模块的方式,将一些切点定义放在同一个类中,比如SystemArchitecture,使用的时候直接引用该切点即可。(再重复下,@PointCut表达式会过滤出所有符合条件的类的方法)。
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("within(com.xyz.someapp.web..*)")
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("within(com.xyz.someapp.service..*)")
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("within(com.xyz.someapp.dao..*)")
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
* "service" package, and that implementation types are in sub-packages.
*
* If you group service interfaces by functional area (for example,
* in packages com.xyz.someapp.abc.service and com.xyz.someapp.def.service) then
* the pointcut expression "execution(* com.xyz.someapp..service.*.*(..))"
* could be used instead.
*
* Alternatively, you can write the expression using the 'bean'
* PCD, like so "bean(*Service)". (This assumes that you have
* named your Spring service beans in a consistent fashion.)
*/
@Pointcut("execution(* com.xyz.someapp..service.*.*(..))")
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
* "dao" package, and that implementation types are in sub-packages.
*/
@Pointcut("execution(* com.xyz.someapp.dao.*.*(..))")
public void dataAccessOperation() {}
}
execution表达式格式
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)
throws-pattern?)
后面带问号的为可选,不带问号是必选。modifiers-pattern就是public这些修饰符;ret-type-pattern为需要匹配的返回值,经常也用来表示匹配任意返回类型;name-pattern表示方法名,也可以用表示匹配任意方法名;declaring-type-pattern表示类型名(即方法所在的类),declaring-type-pattern用 . 连接name-pattern;(param-pattern)代表方法入参,()表示为无参方法,(..)表示0个或多个参数,()代表单个参数的方法,但是可以匹配任意类型,(,String)表示两个参数的方法,第一个参数类型任意,第二个参数为String类型。具体语法,可以参考AspectJ语法文档。
Examples
- The execution of any public method:
execution(public * *(..))
- The execution of any method with a name that begins with set:
execution(* set*(..))
- The execution of any method defined by the AccountService interface:
execution(* com.xyz.service.AccountService.*(..))
- The execution of any method defined in the service package:
execution(* com.xyz.service.*.*(..))
- The execution of any method defined in the service package or one of its sub-packages:
execution(* com.xyz.service..*.*(..))
- Any join point (method execution only in Spring AOP) within the service package:
within(com.xyz.service.*)
- Any join point (method execution only in Spring AOP) within the service package or one of its sub-packages:
within(com.xyz.service..*)
- Any join point (method execution only in Spring AOP) where the proxy implements the AccountService interface:
this(com.xyz.service.AccountService)
- Any join point (method execution only in Spring AOP) where the target object implements the AccountService interface:
target(com.xyz.service.AccountService)
- Any join point (method execution only in Spring AOP) that takes a single parameter and where the argument passed at runtime is Serializable:
args(java.io.Serializable)
Note that the pointcut given in this example is different from execution(* *(java.io.Serializable)). The args version matches if the argument passed at runtime is Serializable, and the execution version matches if the method signature declares a single parameter of type Serializable.
- Any join point (method execution only in Spring AOP) where the target object has a @Transactional annotation:
@target(org.springframework.transaction.annotation.Transactional)
- Any join point (method execution only in Spring AOP) where the declared type of the target object has an @Transactional annotation:
@within(org.springframework.transaction.annotation.Transactional)
- Any join point (method execution only in Spring AOP) where the executing method has an @Transactional annotation:
@annotation(org.springframework.transaction.annotation.Transactional)
- Any join point (method execution only in Spring AOP) which takes a single parameter, and where the runtime type of the argument passed has the @Classified annotation:
@args(com.xyz.security.Classified)
- Any join point (method execution only in Spring AOP) on a Spring bean named tradeService:
bean(tradeService)
- Any join point (method execution only in Spring AOP) on Spring beans having names that match the wildcard expression *Service:
bean(*Service)
Writing Good Pointcuts
如何写出好的PointCuts:
For optimal performance of matching, you should think about what they are trying to achieve and narrow the search space for matches as much as possible in the definition.
一般通过定制更严格的限定条件,尽可能的narrow切点的搜索空间。
AspectJ的PCD包含以下几种(Spring AOP只支持前面提到过的几种):
- Kinded designators select a particular kind of join point: execution, get, set, call, and handler
- Scoping designators select a group of join points of interest (probably of many kinds): within and withincode
- Contextual designators match (and optionally bind) based on context: this, target, and @annotation
@PointCut表达式的好的写法至少包含前两种PCD:Kinded designators和Scoping designators。
网友评论