javascript
Spring中的AOP——在Advice方法中获取目标方法的参数(转)
獲取目標方法的信息
????訪問目標方法最簡單的做法是定義增強處理方法時,將第一個參數(shù)定義為JoinPoint類型,當該增強處理方法被調(diào)用時,該JoinPoint參數(shù)就代表了織入增強處理的連接點。JoinPoint里包含了如下幾個常用的方法:
-
Object[] getArgs:返回目標方法的參數(shù)
-
Signature getSignature:返回目標方法的簽名
-
Object getTarget:返回被織入增強處理的目標對象
-
Object getThis:返回AOP框架為目標對象生成的代理對象
????注意:當使用@Around處理時,我們需要將第一個參數(shù)定義為ProceedingJoinPoint類型,該類是JoinPoint的子類。
????下面的切面類(依然放在com.abc.advice包中)中定義了Before、Around、AfterReturning和After 4中增強處理,并分別在4種增強處理中訪問被織入增強處理的目標方法、目標方法的參數(shù)和被織入增強處理的目標對象等:
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | package?com.abc.advice; import?java.util.Arrays; import?org.aspectj.lang.JoinPoint; import?org.aspectj.lang.ProceedingJoinPoint; import?org.aspectj.lang.annotation.After; import?org.aspectj.lang.annotation.AfterReturning; import?org.aspectj.lang.annotation.Around; import?org.aspectj.lang.annotation.Aspect; import?org.aspectj.lang.annotation.Before; @Aspect public?class?AdviceTest?{ ????@Around("execution(*?com.abc.service.*.many*(..))") ????public?Object?process(ProceedingJoinPoint?point)?throws?Throwable?{ ????????System.out.println("@Around:執(zhí)行目標方法之前..."); ????????//訪問目標方法的參數(shù): ????????Object[]?args?=?point.getArgs(); ????????if?(args?!=?null?&&?args.length?>?0?&&?args[0].getClass()?==?String.class)?{ ????????????args[0]?=?"改變后的參數(shù)1"; ????????} ????????//用改變后的參數(shù)執(zhí)行目標方法 ????????Object?returnValue?=?point.proceed(args); ????????System.out.println("@Around:執(zhí)行目標方法之后..."); ????????System.out.println("@Around:被織入的目標對象為:"?+?point.getTarget()); ????????return?"原返回值:"?+?returnValue?+?",這是返回結(jié)果的后綴"; ????} ????? ????@Before("execution(*?com.abc.service.*.many*(..))") ????public?void?permissionCheck(JoinPoint?point)?{ ????????System.out.println("@Before:模擬權(quán)限檢查..."); ????????System.out.println("@Before:目標方法為:"?+? ????????????????point.getSignature().getDeclaringTypeName()?+? ????????????????"."?+?point.getSignature().getName()); ????????System.out.println("@Before:參數(shù)為:"?+?Arrays.toString(point.getArgs())); ????????System.out.println("@Before:被織入的目標對象為:"?+?point.getTarget()); ????} ????? ????@AfterReturning(pointcut="execution(*?com.abc.service.*.many*(..))",? ????????returning="returnValue") ????public?void?log(JoinPoint?point,?Object?returnValue)?{ ????????System.out.println("@AfterReturning:模擬日志記錄功能..."); ????????System.out.println("@AfterReturning:目標方法為:"?+? ????????????????point.getSignature().getDeclaringTypeName()?+? ????????????????"."?+?point.getSignature().getName()); ????????System.out.println("@AfterReturning:參數(shù)為:"?+? ????????????????Arrays.toString(point.getArgs())); ????????System.out.println("@AfterReturning:返回值為:"?+?returnValue); ????????System.out.println("@AfterReturning:被織入的目標對象為:"?+?point.getTarget()); ????????? ????} ????? ????@After("execution(*?com.abc.service.*.many*(..))") ????public?void?releaseResource(JoinPoint?point)?{ ????????System.out.println("@After:模擬釋放資源..."); ????????System.out.println("@After:目標方法為:"?+? ????????????????point.getSignature().getDeclaringTypeName()?+? ????????????????"."?+?point.getSignature().getName()); ????????System.out.println("@After:參數(shù)為:"?+?Arrays.toString(point.getArgs())); ????????System.out.println("@After:被織入的目標對象為:"?+?point.getTarget()); ????} } |
????在AdviceManager類中增加以下內(nèi)容:
?| 1 2 3 4 5 | //將被AdviceTest的各種方法匹配 public?String?manyAdvices(String?param1,?String?param2)?{ ????System.out.println("方法:manyAdvices"); ????return?param1?+?"?、"?+?param2; } |
????在com.abc.main.AOPTest中加入方法的調(diào)用,觸發(fā)切點:
?| 1 2 | String?result?=?manager.manyAdvices("aa",?"bb"); System.out.println("Test方法中調(diào)用切點方法的返回值:"?+?result); |
????下面是執(zhí)行結(jié)果:
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | @Around:執(zhí)行目標方法之前... @Before:模擬權(quán)限檢查... @Before:目標方法為:com.abc.service.AdviceManager.manyAdvices @Before:參數(shù)為:[改變后的參數(shù)1,?bb] @Before:被織入的目標對象為:com.abc.service.AdviceManager@1dfc617e 方法:manyAdvices @Around:執(zhí)行目標方法之后... @Around:被織入的目標對象為:com.abc.service.AdviceManager@1dfc617e @After:模擬釋放資源... @After:目標方法為:com.abc.service.AdviceManager.manyAdvices @After:參數(shù)為:[改變后的參數(shù)1,?bb] @After:被織入的目標對象為:com.abc.service.AdviceManager@1dfc617e @AfterReturning:模擬日志記錄功能... @AfterReturning:目標方法為:com.abc.service.AdviceManager.manyAdvices @AfterReturning:參數(shù)為:[改變后的參數(shù)1,?bb] @AfterReturning:返回值為:原返回值:改變后的參數(shù)1?、?bb,這是返回結(jié)果的后綴 @AfterReturning:被織入的目標對象為:com.abc.service.AdviceManager@1dfc617e Test方法中調(diào)用切點方法的返回值:原返回值:改變后的參數(shù)1?、bb,這是返回結(jié)果的后綴 |
????從結(jié)果中可以看出:在任何一個織入的增強處理中,都可以獲取目標方法的信息。另外,Spring AOP采用和AspectJ一樣的有限順序來織入增強處理:在“進入”連接點時,最高優(yōu)先級的增強處理將先被織入(所以給定的兩個Before增強處理 中,優(yōu)先級高的那個會先執(zhí)行);在“退出”連接點時,最高優(yōu)先級的增強處理會最后被織入(所以給定的兩個After增強處理中,優(yōu)先級高的那個會后執(zhí) 行)。當不同的切面中的多個增強處理需要在同一個連接點被織入時,Spring AOP將以隨機的順序來織入這些增強處理。如果應(yīng)用需要指定不同切面類里的增強處理的優(yōu)先級,Spring提供了如下兩種解決方案:
-
讓切面類實現(xiàn)org.springframework.core.Ordered接口:實現(xiàn)該接口只需要實現(xiàn)一個int getOrder()方法,該方法返回值越小,優(yōu)先級越高
-
直接使用@Order注解來修飾一個切面類:使用這個注解時可以配置一個int類型的value屬性,該屬性值越小,優(yōu)先級越高
????優(yōu)先級高的切面類里的增強處理的優(yōu)先級總是比優(yōu)先級低的切面類中的增強處理的優(yōu)先級高。例如:優(yōu)先級為1的切面類Bean1包含了@Before,優(yōu)先級為2的切面類Bean2包含了@Around,雖然@Around優(yōu)先級高于@Before,但由于Bean1的優(yōu)先級高于Bean2的優(yōu)先級,因此Bean1中的@Before先被織入。
????同一個切面類里的兩個相同類型的增強處理在同一個連接點被織入時,Spring AOP將以隨機的順序來織入這兩個增強處理,沒有辦法指定它們的織入順序。如果確實需要保證它們以固有的順序被織入,則可以考慮將多個增強處理壓縮為一個增強處理;或者將不同增強處理重構(gòu)到不同切面中,通過在切面級別上定義順序。
????如果只要訪問目標方法的參數(shù),Spring還提供了一種更加簡潔的方法:我們可以在程序中使用args來綁定目標方法的參數(shù)。如果在一個 args表達式中指定了一個或多個參數(shù),該切入點將只匹配具有對應(yīng)形參的方法,且目標方法的參數(shù)值將被傳入增強處理方法。下面輔以例子說明:
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | package?com.abc.advice; import?java.util.Date; import?org.aspectj.lang.annotation.AfterReturning; import?org.aspectj.lang.annotation.Aspect; @Aspect public?class?AccessArgAdviceTest?{ ????@AfterReturning( ????????????pointcut="execution(*?com.abc.service.*.access*(..))?&&?args(time,?name)", ????????????returning="returnValue") ????public?void?access(Date?time,?Object?returnValue,?String?name)?{ ????????System.out.println("目標方法中的參數(shù)String?=?"?+?name); ????????System.out.println("目標方法中的參數(shù)Date?=?"?+?time); ????????System.out.println("目標方法的返回結(jié)果returnValue?=?"?+?returnValue); ????} } |
????上面的程序中,定義pointcut時,表達式中增加了 args(time, name)部分,意味著可以在增強處理方法(access方法)中定義time和name兩個屬性——這兩個形參的類型可以隨意指定,但一旦指定了這兩個 參數(shù)的類型,則這兩個形參類型將用于限制該切入點只匹配第一個參數(shù)類型為Date,第二個參數(shù)類型為name的方法(方法參數(shù)個數(shù)和類型若有不同均不匹配)。
????注意,在定義returning的時候,這個值(即上面的returning="returnValue"中的returnValue)作為增強處理方法的形參時,位置可以隨意,即:如果上面access方法的簽名可以為
?| 1 | public?void?access(Date?time,?Object?returnValue,?String?name) |
????也可以為
?| 1 | public?void?access(Object?returnValue,?Date?time,?String?name) |
????還可以為
?| 1 | public?void?access(Date?time,?String?name,?Object?returnValue) |
????只需要滿足另外的參數(shù)名的順序和pointcut中args(param1, param2)的順序相同即可。我們在AdviceManager中定義一個方法,該方法的第一個參數(shù)為Date類型,第二個參數(shù)為String類型,該 方法的執(zhí)行將觸發(fā)上面的access方法,如下:
?| 1 2 3 4 5 | //將被AccessArgAdviceTest的access方法匹配 public?String?accessAdvice(Date?d,?String?n)?{ ????System.out.println("方法:accessAdvice"); ????return?"aa"; } |
????在AOPTest中增加調(diào)用這個accessAdvice方法并執(zhí)行,下面是輸出結(jié)果:
????從執(zhí)行結(jié)果可以看出,使用args表達式有如下兩個作用:
-
提供了一種簡單的方式來訪問目標方法的參數(shù)
-
可用于對切入點表達式作額外的限制
????除此之外,使用args表達式時,還可以使用如下形式:args(param1, param2, ..),注意args參數(shù)中后面的兩個點,它表示可以匹配更多參數(shù)。在例子args(param1, param2, ..)中,表示目標方法只需匹配前面param1和param2的類型即可。
?
轉(zhuǎn)載于:https://www.cnblogs.com/cornucopia/p/4535725.html
總結(jié)
以上是生活随笔為你收集整理的Spring中的AOP——在Advice方法中获取目标方法的参数(转)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 优酷怎么更换手机号码(优酷客户端下载中心
- 下一篇: javascript提示抖动实现方法