javascript
Spring-AOP @AspectJ语法基础
文章目錄
- 概述
- 切點(diǎn)表達(dá)式函數(shù)
- 方法切點(diǎn)函數(shù)
- execution()
- @annotation()
- 方法入?yún)⑶悬c(diǎn)函數(shù)
- args()
- @args()
- 目標(biāo)類切點(diǎn)函數(shù)
- within()
- target()
- @within()
- @target()
- 代理類切點(diǎn)函數(shù)
- this
- 注意事項(xiàng)
- 在函數(shù)入?yún)⒅惺褂猛ㄅ浞?/li>
- `*`
- `..`
- `+`
- 邏輯運(yùn)算符
- &&
- ||
- !
- 不同增強(qiáng)類型
- @Before
- @AfterReturning
- @Around
- @AfterThrowing
- @After
- @DeclareParents
- 引介增強(qiáng)用法
概述
@AspectJ使用Java5.0注解和正規(guī)的AspectJ的切點(diǎn)表達(dá)式語(yǔ)言描述切面, 由于Spring只支持方法的連接點(diǎn),所以Spring僅支持部分AspectJ的切點(diǎn)語(yǔ)言。
下文闡述的AspectJ切點(diǎn)表達(dá)式語(yǔ)言,以AspectJ5.0版本為準(zhǔn)。
切點(diǎn)表達(dá)式函數(shù)
AspectJ5.0的切點(diǎn)表達(dá)式由關(guān)鍵字和操作參數(shù)組成.
比如 execution(* greetTo(..)) , execution為關(guān)鍵字, * greetTo(..) 為操作參數(shù)。
在這里execution代表目標(biāo)類執(zhí)行某一方法,而 * greetTo(…)描述目標(biāo)方法的匹配模式串,二者聯(lián)合起來(lái)標(biāo)識(shí)目標(biāo)類greetTo()方法的連接點(diǎn)。 為了方便描述,將execution()稱為函數(shù),而將匹配串 * greetTo(..)稱作函數(shù)的入?yún)ⅰ?/font>
Spring支持9個(gè)@AspectJ切點(diǎn)表達(dá)式函數(shù),它們用不同的方式描述目標(biāo)類的連接點(diǎn)
根據(jù)描述對(duì)象的不同,大致可以分為4類
-
方法切點(diǎn)函數(shù):通過(guò)描述目標(biāo)類方法的信息定義連接點(diǎn)
-
方法入?yún)⑶悬c(diǎn)函數(shù):通過(guò)描述目標(biāo)類方法入?yún)⒌男畔⒍x連接點(diǎn)
-
目標(biāo)類切點(diǎn)函數(shù):通過(guò)描述目標(biāo)類類型的信息定義連接點(diǎn)
-
代理類切點(diǎn)函數(shù):通過(guò)描述目標(biāo)類的代理類的信息定義連接點(diǎn)
下面我們來(lái)看下具體的函數(shù)
方法切點(diǎn)函數(shù)
execution()
入?yún)?#xff1a;方法匹配模式串
說(shuō)明:表示滿足某一匹配模式的所有目標(biāo)類方法連接點(diǎn),如 execution(* greetTo(…))表示所有目標(biāo)類中的greetTo()方法,greetTo()方法可以帶帶任意的入?yún)⒑腿我獾姆祷刂?/p>
@annotation()
入?yún)?#xff1a;方法注解類名
說(shuō)明:表示標(biāo)注了某特定注解的目標(biāo)類方法連接點(diǎn), 比如@annotation(com.xgj.annotation.NeedTest)表示任何標(biāo)注了@NeedTest注解的目標(biāo)類方法。
方法入?yún)⑶悬c(diǎn)函數(shù)
args()
入?yún)?#xff1a;類名
說(shuō)明:通過(guò)判斷目標(biāo)類方法運(yùn)行時(shí)入?yún)?duì)象的類型定義指定連接點(diǎn),如args(com.xgj.Waiter)表示所有有且僅有一個(gè)按類型匹配于Waiter入?yún)⒌姆椒ā?/p>
@args()
入?yún)?#xff1a;類型注解類型
說(shuō)明:通過(guò)判斷目標(biāo)類方法運(yùn)行時(shí)入?yún)?duì)象的類是否標(biāo)注了特定的注解指定連接點(diǎn)。 比如@args(com.xgj.Monitor)表示任何這樣的一個(gè)目標(biāo)方法,它有一個(gè)入?yún)⑶胰雲(yún)?duì)象的類標(biāo)注@Monitor注解
目標(biāo)類切點(diǎn)函數(shù)
within()
入?yún)?#xff1a;類名匹配串
說(shuō)明:表示特定域下的所有連接點(diǎn),比如 within(com.xgj.service.*)表示com.xgj.service包中所有的連接點(diǎn),即包中所有類的所有方法; 而 within(com.xgj.service.*Service)表示在com.xgj.service包中所有以Service結(jié)尾的類的所有連接點(diǎn)
target()
入?yún)?#xff1a;類名
說(shuō)明:假如目標(biāo)類按類型匹配與指定類,則目標(biāo)類的所有連接點(diǎn)匹配這個(gè)切點(diǎn)。 比如通過(guò)target(com.xgj.Waiter)定義的切點(diǎn),Waiter及Waiter實(shí)現(xiàn)類NaiveWaiter中的所有連接點(diǎn)都匹配該切點(diǎn)
@within()
入?yún)?#xff1a;類型注解類名
說(shuō)明:假如目標(biāo)類按類型匹配于某個(gè)類A,且類A標(biāo)注了特定的注解,這目標(biāo)類的所有連接點(diǎn)匹配這個(gè)切點(diǎn)。 比如@within(com.xgj.Monitor)定義的切點(diǎn),加入Waiter實(shí)現(xiàn)了@Monitor注解,這Waiter及Waiter的實(shí)現(xiàn)類NaiveWaiter的說(shuō)喲連接點(diǎn)都匹配這個(gè)切點(diǎn)
@target()
入?yún)?#xff1a;類型注解類名
說(shuō)明:假如目標(biāo)類標(biāo)注了特定注解,則目標(biāo)類的所有連接點(diǎn)都匹配該切點(diǎn)。 如@target(com.xgj.Monitor),假設(shè)NaiveWaiter標(biāo)注了@Monitor注解,則NaiveWaiter的所有連接點(diǎn)都匹配這個(gè)切點(diǎn)
代理類切點(diǎn)函數(shù)
this
入?yún)?#xff1a;類名
說(shuō)明:代理類按類型匹配于指定類,則被代理的目標(biāo)類的所有連接點(diǎn)都匹配該切點(diǎn)。
注意事項(xiàng)
除了上述的函數(shù)外,@AspectJ還有其它的函數(shù) ,比如call()、initialization()等,但是不能夠在Spring中使用,否則會(huì)拋出IllegalArgumentException異常。
在函數(shù)入?yún)⒅惺褂猛ㄅ浞?/h1>
有些函數(shù)的入?yún)⒖梢越邮芡ㄅ浞?#xff0c;@AspectJ支持三種通配符
*
* 表示匹配任意字符,但它只能匹配上下文中的一個(gè)元素
..
..表示匹配任意字符,可以匹配上下文中的 多個(gè)元素, 但在標(biāo)識(shí)類時(shí),必須和 * 聯(lián)合使用,而在表示入?yún)r(shí)則單獨(dú)使用
+
+表示按照類型匹配指定類的所有類,必須跟在類名后面,比如com.xgj.Service+。 繼承或擴(kuò)展指定類的所有類,同時(shí)還包含指定類本身。
##支持通配符的函數(shù)說(shuō)明
-
支持所有通配符 execution()和within() , 比如within(com.xgj.*) within(com.xgj.service..*.*Service+)
-
僅支持“+”通配符: args()、this()和target(). 比如args(com.xgj.Waiter+) 、target(java.util.List+)等。 雖然支持+通配符,但是意義不大。 對(duì)于這些函數(shù)來(lái)講使用+和不使用+是等價(jià)的
-
不支持通配符: @args()、@within、@target 和 @annotation.
此外,args() this() target() @args() @within() @target() @annotation() 這7個(gè)函數(shù)除了可以指定類名外,也可以指定變量名,并將目標(biāo)對(duì)象中的變量綁定到增強(qiáng)的方法中。
邏輯運(yùn)算符
切點(diǎn)表達(dá)式由切點(diǎn)函數(shù)組成,切點(diǎn)函數(shù)之間可以進(jìn)行邏輯運(yùn)算,組成復(fù)合切點(diǎn)。
Spring支持以下切點(diǎn)運(yùn)算符
&&
與操作符,相當(dāng)于切點(diǎn)的交集運(yùn)算。
如果在Spring的XML配置文件中使用切點(diǎn)表達(dá)式,由于&是XML特殊字符,所以使用轉(zhuǎn)義字符串&&表示。
為了方便,Spring提供了一個(gè)等效的運(yùn)算符and, 比如within(com.xgj..*) and args(String) 表示在com.xgj包下所有類(當(dāng)前包以及子孫包)擁有一個(gè)String入?yún)⒌姆椒?#xff1b;
||
或操作符,相當(dāng)于切點(diǎn)的并集運(yùn)算,or是等效的操作符。如within(com.xgj..*) || args(String) 表示在com.xgj包下的所有類的方法,或者所有擁有一個(gè)String入?yún)⒌姆椒?#xff1b;
!
非操作符,相當(dāng)于切點(diǎn)的反集運(yùn)算,not是等效的操作符。如!within(com.xgj.*) 表示所有不在com.xgj包下的方法。
注意:
在Spring中使用and or 和 not操作符時(shí),允許不在前面添加空格,比如within(com.xgj..*)andnotargs(String) 和 within(com.xgj..*) and not args(String)是等效的,不過(guò)為了程序的可讀性,我們還是要求在操作符的前后添加空格。
另外,如果not位于切點(diǎn)表達(dá)式的開(kāi)頭,則必須在開(kāi)頭添加一個(gè)空格,否則會(huì)產(chǎn)生解析錯(cuò)誤。 比如 not within(com.xgj..*)
不同增強(qiáng)類型
@AspectJ為各種的增強(qiáng)類型提供了不同的注解類,它們位于org.aspectj.lang.annotation.*包中,這些注解類擁有若干個(gè)成員,可以通過(guò)這些成員完成定義切點(diǎn)信息、綁定連接點(diǎn)參數(shù)等操作;
此外,這些注解的存留期限都是RetentionPolicy.RUNTIME,標(biāo)注目標(biāo)都是ElementType.METHOD。
@Before
前置增強(qiáng),相當(dāng)于BeforeAdvice的功能,
Before注解類擁有兩個(gè)成員:
-
value:該成員用于定義切點(diǎn);
-
argNames:由于無(wú)法通過(guò)Java反射機(jī)制獲取方法入?yún)⒚?#xff0c;所有如果在Java編譯時(shí)未啟動(dòng)調(diào)試信息或者需要在運(yùn)行期解析切點(diǎn),就必須通過(guò)這個(gè)成員指定注解所標(biāo)注增強(qiáng)方法的參數(shù)名(注意兩者名字必須完全相同),多個(gè)參數(shù)名用逗號(hào)分隔。
@AfterReturning
后置增強(qiáng),相當(dāng)于AfterReturningAdvice,
AfterReturning注解類擁有4個(gè)成員:
-
value:該成員用于定義切點(diǎn);
-
pointcut:表示切點(diǎn)的信息,如果顯式指定pointcut值,它將覆蓋value的設(shè)置值,可以將pointcut成員看成是value的同義詞;
-
returning:將目標(biāo)對(duì)象方法的返回值綁定給增強(qiáng)的方法;
-
argNames:如前所述。
@Around
環(huán)繞增強(qiáng),相當(dāng)于MethodInterceptor,
Around注解類擁有兩個(gè)成員:
-
value:該成員用于定義切點(diǎn);
-
argNames:如前所述。
@AfterThrowing
拋出增強(qiáng),相當(dāng)于ThrowsAdvice.
AfterThrowing注解類擁有4個(gè)成員:
-
value:該成員用于定義切點(diǎn);
-
pointcut:表示切點(diǎn)的信息,如果顯式指定pointcut值,它將覆蓋value的設(shè)置值,可以將pointcut成員看成是value的同義詞;
-
throwing:將拋出的異常綁定到增強(qiáng)方法中;
-
argNames:如前所述。
@After
Final增強(qiáng),不管是拋出異常或者是正常退出,該增強(qiáng)都會(huì)得到執(zhí)行,該增強(qiáng)沒(méi)有對(duì)應(yīng)的增強(qiáng)接口,可以把它看成是ThrowsAdvice和AfterReturningAdvice的混合物,一般用于釋放資源,相當(dāng)于try{}finally{}的控制流。
After注解類擁有兩個(gè)成員:
-
value:該成員用于定義切點(diǎn);
-
argNames:如前所述。
@DeclareParents
引介增強(qiáng),相當(dāng)于IntroductionInterceptor,
DeclareParents注解類擁有兩個(gè)成員:
-
value:該成員用于定義切點(diǎn),它表示在哪個(gè)目標(biāo)類上添加引介增強(qiáng);
-
defaultImpl:默認(rèn)的接口實(shí)現(xiàn)類。
引介增強(qiáng)用法
代碼已托管到Github—> https://github.com/yangshangwei/SpringMaster
假設(shè)我們希望Waiter能夠同時(shí)充當(dāng)Seller的角色,即通過(guò)切面技術(shù)為NaiveWaiter新增Seller接口的實(shí)現(xiàn)。
下面我們使用@AspectJ的引介增強(qiáng)來(lái)實(shí)現(xiàn)這一個(gè)功能。
package com.xgj.aop.spring.advisor.aspectJ.basic;import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.DeclareParents;/*** * * @ClassName: EnableSellerAspect* * @Description: 希望Waiter也能同時(shí)充當(dāng)Seller的角色* * @author: Mr.Yang* * @date: 2017年8月26日 上午1:23:41*/@Aspect public class EnableSellerAspect {// (1)value 為NaiveWaiter添加接口實(shí)現(xiàn), (2)defaultImpl默認(rèn)的接口實(shí)現(xiàn)類@DeclareParents(value = "com.xgj.aop.spring.advisor.aspectJ.basic.NaiveWaiter", defaultImpl = SmartSeller.class)public Seller seller; // (3) 要實(shí)現(xiàn)的目標(biāo)接口 }分析:
在EnableSellerAspect 切面中,通過(guò)@DeclareParents為NaiveWaiter添加了一個(gè)需要實(shí)現(xiàn)的Seller接口,并指定其默認(rèn)實(shí)現(xiàn)類為SmartSeller. 然后通過(guò)切面技術(shù)將SmartSeller融合到NaiveWaiter中,這樣NaiveWaiter就實(shí)現(xiàn)了Seller接口。
配置文件,配置切面和NaiveWaiter Bean
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 使用基于Schema的aop命名空間進(jìn)行配置 --><!-- 基于@AspectJ切面的驅(qū)動(dòng)器 --> <aop:aspectj-autoproxy/><!-- 目標(biāo)Bean --> <bean id="waiter" class="com.xgj.aop.spring.advisor.aspectJ.basic.NaiveWaiter"/> <!-- 使用了@AspectJ注解的切面類 --> <bean class="com.xgj.aop.spring.advisor.aspectJ.basic.EnableSellerAspect"/></beans>測(cè)試類:
package com.xgj.aop.spring.advisor.aspectJ.basic;import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class EnableSellerAspectTest {@Testpublic void test() {ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:com/xgj/aop/spring/advisor/aspectJ/basic/conf-aspectJ.xml");Waiter waiter = ctx.getBean("waiter", Waiter.class);waiter.greetTo("XiaoGongJiang");// 可以成功的進(jìn)行強(qiáng)制類型轉(zhuǎn)換Seller seller = (Seller) waiter;seller.sell("beer", "XiaoGongJiang");} }運(yùn)行結(jié)果:
2017-08-26 01:42:50,077 INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@24b9371e: startup date [Sat Aug 26 01:42:50 BOT 2017]; root of context hierarchy 2017-08-26 01:42:50,173 INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/aspectJ/basic/conf-aspectJ.xml] NaiveWaiter Greet to XiaoGongJiang SmartSeller: sell beer to XiaoGongJiang可見(jiàn),NaiveWaiter已經(jīng)成功的新增了Seller接口的實(shí)現(xiàn)。
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的Spring-AOP @AspectJ语法基础的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Spring-AOP 自动创建代理之An
- 下一篇: Spring-AOP @AspectJ切