javascript
Spring AOP 切点(pointcut)表达式
概括
這遍文章將介紹Spring AOP切點(diǎn)表達(dá)式(下稱表達(dá)式)語(yǔ)言,首先介紹兩個(gè)面向切面編程中使用到的術(shù)語(yǔ)。
-
連接點(diǎn)(Joint Point):廣義上來(lái)講,方法、異常處理塊、字段這些程序調(diào)用過(guò)程中可以抽像成一個(gè)執(zhí)行步驟(或者說(shuō)執(zhí)行點(diǎn))的單元。從Spring AOP來(lái)講,就是指java的方法和異常處理代碼塊。
- 切點(diǎn)(Pointcut):是連接點(diǎn)的描述定義,Spring AOP通過(guò)切點(diǎn)來(lái)定位到哪些連接點(diǎn)。切點(diǎn)表達(dá)式語(yǔ)言就是切點(diǎn)用來(lái)定義連接點(diǎn)的語(yǔ)法。
用例
表達(dá)式會(huì)出現(xiàn)在以下幾種場(chǎng)景
在上面的代碼片段中的注解@Pointcut的參數(shù)"within(@org.springframework.stereotype.Reposity *)"就是使用的切點(diǎn)表達(dá)式。而上代碼中的repositoryClassMethods()方法被AOP AspectJ定義為切點(diǎn)簽名方法,作用是使得通知的注解可以通過(guò)這個(gè)切點(diǎn)簽名方法連接到切點(diǎn),通過(guò)解釋切點(diǎn)表達(dá)式找到需要被切入的連接點(diǎn)。最終的目的都是為了找到需要被切入的連接點(diǎn)。像下面這段代碼片段
如果你的項(xiàng)目是基于xml配置的,可以在<aop:pointcut>標(biāo)簽里配置表達(dá)式來(lái)定位連接點(diǎn),參考以下代碼片段:
<aop:config><aop:pointcut id="anyDaoMethod"expression="@target(org.springframework.stereotype.Repository)"/> </aop:config>切點(diǎn)指示符
切點(diǎn)指示符是切點(diǎn)定義的關(guān)鍵字,切點(diǎn)表達(dá)式以切點(diǎn)指示符開始。開發(fā)人員使切點(diǎn)指示符來(lái)告訴切點(diǎn)將要匹配什么,有以下9種切點(diǎn)指示符:execution、within、this、target、args、@target、@args、@within、@annotation,下面一一介結(jié)這9種切點(diǎn)指示符。
execution
execution是一種使用頻率比較高比較主要的一種切點(diǎn)指示符,用來(lái)匹配方法簽名,方法簽名使用全限定名,包括訪問(wèn)修飾符(public/private/protected)、返回類型,包名、類名、方法名、參數(shù),其中返回類型,包名,類名,方法,參數(shù)是必須的,如下面代碼片段所示:
@Pointcut("execution(public String org.baeldung.dao.FooDao.findById(Long))")上面的代碼片段里的表達(dá)式精確地匹配到FooDao類里的findById(Long)方法,但是這看起來(lái)不是很靈活。假設(shè)我們要匹配FooDao類的所有方法,這些方法可能會(huì)有不同的方法名,不同的返回值,不同的參數(shù)列表,為了達(dá)到這種效果,我們可以使用通配符。如下代碼片段所示:
@Pointcut("execution(* org.baeldung.dao.FooDao.*(..))")第一個(gè)通配符匹配所有返回值類型,第二個(gè)匹配這個(gè)類里的所有方法,()括號(hào)表示參數(shù)列表,括號(hào)里的用兩個(gè)點(diǎn)號(hào)表示匹配任意個(gè)參數(shù),包括0個(gè)
within
使用within切點(diǎn)批示符可以達(dá)到上面例子一樣的效果,within用來(lái)限定連接點(diǎn)屬于某個(gè)確定類型的類。如下面代碼的效果與上面的例子是一樣的:
@Pointcut("within(org.baeldung.dao.FooDao)")我們也可以使用within指示符來(lái)匹配某個(gè)包下面所有類的方法(包括子包下面的所有類方法),如下代碼所示:
@Pointcut("within(org.baeldung..*)")this 和 target
this用來(lái)匹配的連接點(diǎn)所屬的對(duì)象引用是某個(gè)特定類型的實(shí)例,target用來(lái)匹配的連接點(diǎn)所屬目標(biāo)對(duì)象必須是指定類型的實(shí)例;那么這兩個(gè)有什么區(qū)別呢?原來(lái)AspectJ在實(shí)現(xiàn)代理時(shí)有兩種方式:
1、如果當(dāng)前對(duì)象引用的類型沒(méi)有實(shí)現(xiàn)自接口時(shí),spring aop使用生成一個(gè)基于CGLIB的代理類實(shí)現(xiàn)切面編程
2、如果當(dāng)前對(duì)象引用實(shí)現(xiàn)了某個(gè)接口時(shí),Spring aop使用JDK的動(dòng)態(tài)代理機(jī)制來(lái)實(shí)現(xiàn)切面編程
this指示符就是用來(lái)匹配基于CGLIB的代理類,通俗的來(lái)講就是,如果當(dāng)前要代理的類對(duì)象沒(méi)有實(shí)現(xiàn)某個(gè)接口的話,則使用this;target指示符用于基于JDK動(dòng)態(tài)代理的代理類,通俗的來(lái)講就是如果當(dāng)前要代理的目標(biāo)對(duì)象有實(shí)現(xiàn)了某個(gè)接口的話,則使用target.:
比如在上面這段代碼示例中,spring aop將使用jdk的動(dòng)態(tài)代理來(lái)實(shí)現(xiàn)切面編程,在編寫匹配這類型的目標(biāo)對(duì)象的連接點(diǎn)表達(dá)式時(shí)要使用target指示符, 如下所示:
@Pointcut("target(org.baeldung.dao.BarDao)")如果FooDao類沒(méi)有實(shí)現(xiàn)任何接口,或者在spring aop配置屬性:proxyTargetClass設(shè)為true時(shí),Spring Aop會(huì)使用基于CGLIB的動(dòng)態(tài)字節(jié)碼技為目標(biāo)對(duì)象生成一個(gè)子類將為代理類,這時(shí)應(yīng)該使用this指示器:
@Pointcut("this(org.baeldung.dao.FooDao)")參數(shù)
參數(shù)指示符是一對(duì)括號(hào)所括的內(nèi)容,用來(lái)匹配指定方法參數(shù):
@Pointcut("execution(* *..find*(Long))")這個(gè)切點(diǎn)匹配所有以find開頭的方法,并且只一個(gè)Long類的參數(shù)。如果我們想要匹配一個(gè)有任意個(gè)參數(shù),但是第一個(gè)參數(shù)必須是Long類的,我們這可使用下面這個(gè)切點(diǎn)表達(dá)式:
@Pointcut("execution(* *..find*(Long,..))")@Target
這個(gè)指示器匹配指定連接點(diǎn),這個(gè)連接點(diǎn)所屬的目標(biāo)對(duì)象的類有一個(gè)指定的注解:
@Pointcut("@target(org.springframework.stereotype.Repository)")@args
這個(gè)指示符是用來(lái)匹配連接點(diǎn)的參數(shù)的,@args指出連接點(diǎn)在運(yùn)行時(shí)傳過(guò)來(lái)的參數(shù)的類必須要有指定的注解,假設(shè)我們希望切入所有在運(yùn)行時(shí)接受實(shí)@Entity注解的bean對(duì)象的方法:
@Pointcut("@args(org.baeldung.aop.annotations.Entity)") public void methodsAcceptingEntities() {}為了在切面里接收并使用這個(gè)被@Entity的對(duì)象,我們需要提供一個(gè)參數(shù)給切面通知:JointPoint:
@Before("methodsAcceptingEntities()") public void logMethodAcceptionEntityAnnotatedBean(JoinPoint jp) {logger.info("Accepting beans with @Entity annotation: " + jp.getArgs()[0]); }@within
這個(gè)指示器,指定匹配必須包括某個(gè)注解的的類里的所有連接點(diǎn):
@Pointcut("@within(org.springframework.stereotype.Repository)")上面的切點(diǎn)跟以下這個(gè)切點(diǎn)是等效的:
@Pointcut("within(@org.springframework.stereotype.Repository *)")@annotation
這個(gè)指示器匹配那些有指定注解的連接點(diǎn),比如,我們可以新建一個(gè)這樣的注解@Loggable:
@Pointcut("@annotation(org.baeldung.aop.annotations.Loggable)") public void loggableMethods() {}我們可以使用@Loggable注解標(biāo)記哪些方法執(zhí)行需要輸出日志:
@Before("loggableMethods()") public void logMethod(JoinPoint jp) {String methodName = jp.getSignature().getName();logger.info("Executing method: " + methodName); }切點(diǎn)表達(dá)式組合
可以使用&&、||、!、三種運(yùn)算符來(lái)組合切點(diǎn)表達(dá)式,表示與或非的關(guān)系。
@Pointcut("@target(org.springframework.stereotype.Repository)") public void repositoryMethods() {}@Pointcut("execution(* *..create*(Long,..))") public void firstLongParamMethods() {}@Pointcut("repositoryMethods() && firstLongParamMethods()") public void entityCreationMethods() {}作者的github例子:https://github.com/eugenp/tutorials/tree/master/spring-mvc-java
from:http://blog.51cto.com/5914679/2092253?
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的Spring AOP 切点(pointcut)表达式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: RabbitMQ系统3.5.3版本中文完
- 下一篇: Spring AOP切点表达式详解