@Pointcut語法詳解
https://www.mekau.com/4880.html
https://blog.csdn.net/xiaoyiaoyou/article/details/45972363
定義
格式:@ 註解(value=“表達標籤 ( 表達式格式)”)
如:@Pointcut (value=“execution(* com.cn.spring.aspectj.NotVeryUsefulAspectService.*(…))”)
表達式標籤
- execution():用於匹配方法執行的連接點
- args(): 用於匹配當前執行的方法傳入的參數爲指定類型的執行方法
- this(): 用於匹配當前AOP代理對象類型的執行方法;注意是AOP代理對象的類型匹配,這樣就可能包括引入接口也類型匹配;
- target(): 用於匹配當前目標對象類型的執行方法;注意是目標對象的類型匹配,這樣就不包括引入接口也類型匹配;
- within(): 用於匹配指定類型內的方法執行;
- @args():於匹配當前執行的方法傳入的參數持有指定註解的執行;
- @target():用於匹配當前目標對象類型的執行方法,其中目標對象持有指定的註解;
- @within():用於匹配所以持有指定註解類型內的方法;
- @annotation:用於匹配當前執行方法持有指定註解的方法;
其中execution 是用的最多的,
execution
execution格式:
execution(modifier-pattern?
ret-type-pattern
declaring-type-pattern?
name-pattern(param-pattern)
throws-pattern?)
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
其中帶 ?號的 modifiers-pattern?,declaring-type-pattern?,hrows-pattern?是可選項
ret-type-pattern,name-pattern, parameters-pattern是必選項;
- modifier-pattern? 修飾符匹配,如public 表示匹配公有方法
- ret-type-pattern 返回值匹配,* 表示任何返回值,全路徑的類名等
- declaring-type-pattern? 類路徑匹配
- name-pattern 方法名匹配,* 代表所有,set*,代表以set開頭的所有方法
- (param-pattern) 參數匹配,指定方法參數(聲明的類型),
(…)代表所有參數,
()代表一個參數,
(,String)代表第一個參數爲任何值,第二個爲String類型. - throws-pattern? 異常類型匹配
例子:
- execution(public * *(..)) 定義任意公共方法的執行
- execution(* set*(..)) 定義任何一個以"set"開始的方法的執行
- execution(* com.xyz.service.AccountService.*(..)) 定義AccountService 接口的任意方法的執行
- execution(* com.xyz.service.*.*(..)) 定義在service包裏的任意方法的執行
- execution(* com.xyz.service ..*.*(..)) 定義在service包和所有子包裏的任意類的任意方法的執行
- execution(* com.test.spring.aop.pointcutexp…JoinPointObjP2.*(…)) 定義在pointcutexp包和所有子包裏的JoinPointObjP2類的任意方法的執行:
AspectJ類型匹配的通配符:
- *
- . .
- +:
如:
- java.lang.String 匹配String類型;
- java.*.String 匹配java包下的任何“一級子包”下的String類型;如匹配java.lang.String,但不匹配java.lang.ss.String
- java..* 匹配java包及任何子包下的任何類型; 如匹配java.lang.String、java.lang.annotation.Annotation
- java.lang.*ing 匹配任何java.lang包下的以ing結尾的類型;
- java.lang.Number+ 匹配java.lang包下的任何Number的自類型;如匹配java.lang.Integer,也匹配java.math.BigInteger
within和@within
- within(com.test.spring.aop.pointcutexp.*) pointcutexp包裏的任意類.
- within(com.test.spring.aop.pointcutexp…*) pointcutexp包和所有子包裏的任意類.
- @within(org.springframework.transaction.annotation.Transactional) 帶有@Transactional標註的所有類的任意方法.
this
- this(com.test.spring.aop.pointcutexp.Intf) 實現了Intf接口的所有類,如果Intf不是接口,限定Intf單個類.
@target
- @target(org.springframework.transaction.annotation.Transactional) 帶有@Transactional標註的所有類的任意方法.
@annotation
- @annotation(org.springframework.transaction.annotation.Transactional) 帶有@Transactional標註的任意方法.
args 和 @args
- @args(org.springframework.transaction.annotation.Transactional) 參數帶有@Transactional標註的方法.
- args(String) 參數爲String類型(運行是決定)的方法.
命名及匿名切入點
@Pointcut("execution(* com.savage.aop.MessageSender.*(..)) && args(param)")
public void log(){
}
@Before("log(String param)")
public void beforeLog(){
//todo something....
}
//等同於
@Before("execution(* com.savage.aop.MessageSender.*(..)) && args(param)")
public void beforeLog(){
//todo something....
}
又如:
@Pointcut("execution(* com.savage.aop.MessageSender.*(..))")
private void logSender(){}
@Pointcut("execution(* com.savage.aop.MessageReceiver.*(..))")
private void logReceiver(){}
@Pointcut("logSender() || logReceiver()")
private void logMessage(){}
這個例子中,logMessage()將匹配任何MessageSender和MessageReceiver中的任何方法
切入點使用示例:
- 一、execution:使用“execution(方法表達式)”匹配方法執行;
示例 | 描述 |
---|---|
public * *(…) | 任何公共方法的執行 |
* cn.javass…IPointcutService.*() | cn.javass包及所有子包下IPointcutService接口中的任何無參方法 |
* cn.javass….(…) | cn.javass包及所有子包下任何類的任何方法 |
* cn.javass…IPointcutService.() | cn.javass包及所有子包下IPointcutService接口的任何只有一個參數方法 |
* (!cn.javass…IPointcutService+).*(…) | 非“cn.javass包及所有子包下IPointcutService接口及子類型”的任何方法 |
* cn.javass…IPointcutService+.*() | cn.javass包及所有子包下IPointcutService接口及子類型的的任何無參方法 |
* cn.javass…IPointcut*.test*(java.util.Date) | cn.javass包及所有子包下IPointcut前綴類型的的以test開頭的只有一個參數類型爲java.util.Date的方法,注意該匹配是根據方法簽名的參數類型進行匹配的,而不是根據執行時傳入的參數類型決定的,如定義方法:public void test(Object obj);即使執行時傳入java.util.Date,也不會匹配的; |
* cn.javass…IPointcut*.test*(…) throws IllegalArgumentException,ArrayIndexOutOfBoundsException,cn.javass | 包及所有子包下IPointcut前綴類型的的任何方法,且拋出IllegalArgumentException和ArrayIndexOutOfBoundsException異常 |
* (cn.javass…IPointcutService+&& java.io.Serializable+).*(…) | 任何實現了cn.javass包及所有子包下IPointcutService接口和java.io.Serializable接口的類型的任何方法 |
@java.lang.Deprecated * *(…) | 任何持有@java.lang.Deprecated註解的方法 |
@java.lang.Deprecated @cn.javass…Secure * *(…) | 任何持有@java.lang.Deprecated和@cn.javass…Secure註解的方法 |
@(java.lang.Deprecated | |
(@cn.javass…Secure *) *(…) | 任何返回值類型持有@cn.javass…Secure的方法 |
* (@cn.javass…Secure ).(…) | 任何定義方法的類型持有@cn.javass…Secure的方法 |
* (@cn.javass…Secure () , @cn.javass…Secure (*)) | 任何簽名帶有兩個參數的方法,且這個兩個參數都被@ Secure標記了,如public void test(@Secure String str1, @Secure String str1); |
* *((@ cn.javass…Secure ))或 *(@ cn.javass…Secure *) | 任何帶有一個參數的方法,且該參數類型持有@ cn.javass…Secure; |
如public void test(Model model);且Model類上持有@Secure註解 | |
* *(@cn.javass…Secure (@cn.javass…Secure *) ,@ cn.javass…Secure (@cn.javass…Secure *)) | 任何帶有兩個參數的方法,且這兩個參數都被@ cn.javass…Secure標記了;且這兩個參數的類型上都持有@ cn.javass…Secure; |
* *(java.util.Map<cn.javass…Model, cn.javass…Model>, …) | 任何帶有一個java.util.Map參數的方法,且該參數類型是以< cn.javass…Model, cn.javass…Model >爲泛型參數;注意只匹配第一個參數爲java.util.Map,不包括子類型;如public void test(HashMap<Model, Model> map, String str);將不匹配,必須使用“* *(java.util.HashMap<cn.javass…Model,cn.javass…Model>, …)”進行匹配;而public void test(Map map, int i);也將不匹配,因爲泛型參數不匹配 |
* *(java.util.Collection<@cn.javass…Secure *>) | 任何帶有一個參數(類型爲java.util.Collection)的方法,且該參數類型是有一個泛型參數,該泛型參數類型上持有@cn.javass…Secure註解;如public void test(Collection collection);Model類型上持有@cn.javass…Secure |
* *(java.util.Set<? extends HashMap>) | 任何帶有一個參數的方法,且傳入的參數類型是有一個泛型參數,該泛型參數類型繼承與HashMap;Spring AOP目前測試不能正常工作 |
* *(java.util.List<? super HashMap>) | 任何帶有一個參數的方法,且傳入的參數類型是有一個泛型參數,該泛型參數類型是HashMap的基類型;如public voi test(Map map);Spring AOP目前測試不能正常工作 |
* (<@cn.javass…Secure *>) | 任何帶有一個參數的方法,且該參數類型是有一個泛型參數,該泛型參數類型上持有@cn.javass…Secure註解;Spring AOP目前測試不能正常工作 |
- 二、within:使用“within(類型表達式)”匹配指定類型內的方法執行;
示例 | 描述 |
---|---|
within(cn.javass…*) | cn.javass包及子包下的任何方法執行 |
within(cn.javass…IPointcutService+) | cn.javass包或所有子包下IPointcutService類型及子類型的任何方法 |
within(@cn.javass…Secure *) | 持有cn.javass…Secure註解的任何類型的任何方法必須是在目標對象上聲明這個註解,在接口上聲明的對它不起作用 |
- 三、this:使用“this(類型全限定名)”匹配當前AOP代理對象類型的執行方法;注意是AOP代理對象的類型匹配,這樣就可能包括引入接口方法也可以匹配;注意this中使用的表達式必須是類型全限定名,不支持通配符;
示例 | 描述 |
---|---|
this(cn.javass.spring.chapter6.service.IPointcutService) | 當前AOP對象實現了 IPointcutService接口的任何方法 |
this(cn.javass.spring.chapter6.service.IIntroductionService) | 當前AOP對象實現了 IIntroductionService接口的任何方法 |
- 四、target:使用“target(類型全限定名)”匹配當前目標對象類型的執行方法;注意是目標對象的類型匹配,這樣就不包括引入接口也類型匹配;注意target中使用的表達式必須是類型全限定名,不支持通配符;
示例 | 描述 |
---|---|
target(cn.javass.spring.chapter6.service.IPointcutService) | 當前目標對象(非AOP對象)實現了 IPointcutService接口的任何方法 |
target(cn.javass.spring.chapter6.service.IIntroductionService) | 當前目標對象(非AOP對象) 實現了IIntroductionService 接口的任何方法, 不可能是引入接口 |
- 五、args:使用“args(參數類型列表)”匹配當前執行的方法傳入的參數爲指定類型的執行方法;注意是匹配傳入的參數類型,不是匹配方法簽名的參數類型;參數類型列表中的參數必須是類型全限定名,通配符不支持;args屬於動態切入點,這種切入點開銷非常大,非特殊情況最好不要使用;
示例 | 描述 |
---|---|
args (java.io.Serializable,…) | 任何一個以接受“傳入參數類型爲 java.io.Serializable” 開頭,且其後可跟任意個任意類型的參數的方法執行,args指定的參數類型是在運行時動態匹配的 |
- 六、@within:使用“@within(註解類型)”匹配所以持有指定註解類型內的方法;註解類型也必須是全限定類型名;
示例 | 描述 |
---|---|
@within(cn.javass.spring.chapter6.Secure) | 任何目標對象對應的類型持有Secure註解的類方法; |
- 七、@target:使用“@target(註解類型)”匹配當前目標對象類型的執行方法,其中目標對象持有指定的註解;註解類型也必須是全限定類型名;
示例 | 描述 |
---|---|
@target (cn.javass.spring.chapter6.Secure) | 任何目標對象持有Secure註解的類方法;必須是在目標對象上聲明這個註解,在接口上聲明的對它不起作用 |
- 八、@args:使用“@args(註解列表)”匹配當前執行的方法傳入的參數持有指定註解的執行;註解類型也必須是全限定類型名;
示例 | 描述 |
---|---|
@args (cn.javass.spring.chapter6.Secure) | 任何一個只接受一個參數的方法,且方法運行時傳入的參數持有註解 cn.javass.spring.chapter6.Secure;動態切入點,類似於arg指示符; |
- 九、@annotation:使用“@annotation(註解類型)”匹配當前執行方法持有指定註解的方法;註解類型也必須是全限定類型名;
示例 | 描述 |
---|---|
@annotation(cn.javass.spring.chapter6.Secure ) | 當前執行方法上持有註解 cn.javass.spring.chapter6.Secure將被匹配 |
- 十、bean:使用“bean(Bean id或名字通配符)”匹配特定名稱的Bean對象的執行方法;Spring ASP擴展的,在AspectJ中無相應概念;
示例 | 描述 |
---|---|
bean(*Service) | 匹配所有以Service命名(id或name)結尾的Bean |
- 十一、reference pointcut:表示引用其他命名切入點;
@Pointcut(value="bean(*Service)")
private void pointcut1(){
}
@Pointcut(value="@args()cn.javass.spring.chaper6.Source")
public referencePointcutTest(JoinPoint jp){
...
}
AOP例子
@Aspect
@Component
public class NotVeryUsefulAspect {
@AfterReturning(value="execution(* com.cn.spring.aspectj.NotVeryUsefulAspectService.*(..))")
private void logReceiver(){
System.out.println("切入點logReceiver...");
}
@Pointcut(value="execution(* com.cn.spring.aspectj.NotVeryUsefulAspectService.*(..)) && args(param)")
private void pointcut(String param){
System.out.println("切入點pointcut()"+param);
}
//方法體將不執行
@Pointcut("within(com.cn.spring.aspectj.*)")
public String inWebLayer() {
System.out.println("切入點inWebLayer()");
return "返回值加載";
}
@Before(value="inWebLayer()")
private void beforeinWebLayer(){
System.out.println("beforeinWebLayer~~");
}
@Before(value="pointcut(param)")
private void beforePointcut(String param){
System.out.println("beforePointcut:"+param);
}
@AfterReturning(pointcut="inWebLayer()",returning="retVal")
public void doAccessCheck(Object retVal) {
System.out.println("doAccessCheck:"+retVal);
}
@Around(value="execution(* com.cn.spring.aspectj.NotVeryUsefulAspectService.*(..))")
private Object aroundLayer(ProceedingJoinPoint pjp) throws Throwable{
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
System.out.println("aroundLayer~~");
return retVal;
}
}