javascript
Spring-AOP @AspectJ切点函数之args()和@args()
文章目錄
- 概述
- args()
- @args()
- 實例
- args()
- @args()
概述
args函數的入參是類名, 而 @args()的入參必須是注解類的類名。
雖然args()允許在類名后使用“+”通配符,但該通配符在此處沒有意義,添加和不添加的效果都一樣。
args()
該函數接收一個類名,表示目標類方法入參對象是指定類(包含子類)時,切點匹配。
比如args(com.xgj.Waiter) 表示運行時入參是Waiter類型的方法,它和execution(* *(com.xgj.Waiter))的區別在于后者是這對類方法的簽名而言的,而前者是針對運行時的入參類型而言。
比如args(com.xgj.Waiter)既匹配addWiter(Waiter waiter),又匹配addNaiveWaiter(NaiveWaiter waiter); 而 execution(* *(com.xgj.Waiter)),實際上 args(com.xgj.Waiter)等價于 execution(* *(com.xgj.Waiter+)),當然也等價于 args(com.xgj.Waiter+)
@args()
該函數接收一個注解類的類名,當方法的運行時入參對象標注了指定的注解時,匹配切點。
我們來通過下圖@args(M)匹配示意圖來詳細解釋下:
T0、T1、T2、T3有如上繼承關系,假設目標類方法的簽名為fun(T1 t),它的入參為T1,而切面的切點定義為@args(M), T2類標注了@M。 當fun(T1 t)的傳入對象為T2或者T3時,方法匹配@args(M)聲明所定義的切點。
假設方法簽名是funt(T1 t),入參為T1,而標注了@M的類是T0,當fun(T1 t)傳入T1、T2、T3的實例時,均不匹配切點@args(M).
在類的繼承樹中,(1)處為方法簽名中入參類型在繼承樹的位置,稱之為入參類型點, 而(2)處標注了@M注解的類在類繼承樹中的位置,稱之為注解點。 判斷方法在運行時是否匹配@args(M)切點,可以根據(1)和(2)在類繼承樹中的相對位置來判斷。
- 如果在繼承樹中注解點(2)高于入參類型點(1),則該目標方法不可能匹配到切點@args(M) ,如下圖所示
- 如果在類繼承樹中注解點(2)低于入參類型點(1),則注解點所在類及其子孫類作為方法入參時,該方法匹配切點@args(M)
實例請參考下文。
實例
代碼已托管到Github—> https://github.com/yangshangwei/SpringMaster
args()
POJO
package com.xgj.aop.spring.advisor.aspectJ.function.args;import org.springframework.stereotype.Component;@Component public class UserService {public void addUser(User user) {System.out.println("addUser " + user);}public void modifyUser(User user) {System.out.println("modifyUser " + user);}public void delUser(User user) {System.out.println("delUser " + user);}/*** * * @Title: addArtisanTT* * @Description: 入參為ArtisanTT* * @param artisan* * @return: void*/public void addArtisanTT(ArtisanTT artisan) {System.out.println("addArtisanTT " + artisan);}public void modifyArtisanTT(ArtisanTT artisan) {System.out.println("modifyArtisanTT " + artisan);}public void delArtisanTT(ArtisanTT artisan) {System.out.println("delArtisanTT " + artisan);}}POJO
package com.xgj.aop.spring.advisor.aspectJ.function.args;import org.springframework.stereotype.Component;@Component public class UserServiceExt {public void addUser(User user) {System.out.println("入參為user的類 addUser " + user);}public void modifyUser(User user) {System.out.println("入參為user的類 modifyUser " + user);}public void delUser(User user) {System.out.println("入參為user的類 delUser " + user);}/*** * * @Title: addArtisanTT* * @Description: 入參為ArtisanTT* * @param artisan* * @return: void*/public void addArtisanTT(ArtisanTT artisan) {System.out.println("addArtisanTT " + artisan);}public void modifyArtisanTT(ArtisanTT artisan) {System.out.println("modifyArtisanTT " + artisan);}public void delArtisanTT(ArtisanTT artisan) {System.out.println("delArtisanTT " + artisan);} }切面
package com.xgj.aop.spring.advisor.aspectJ.function.args;import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before;/*** * * @ClassName: ArgsAspectJ* * @Description: 該函數接收一個類名,表示目標類方法入參對象是指定類(包含子類)時,切點匹配* * @author: Mr.Yang* * @date: 2017年9月1日 上午11:36:23*/@Aspect public class ArgsAspect {@Before("args(com.xgj.aop.spring.advisor.aspectJ.function.args.User)")public void crossCuttingCode() {System.out.println("some logic is here ");} }配置文件
<?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"xmlns:context="http://www.springframework.org/schema/context"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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- (1)聲明Context命名空間以及Schema文件 (2)掃描類包以及應用注解定義的bean --> <context:component-scan base-package="com.xgj.aop.spring.advisor.aspectJ.function.args"/><!-- 基于@AspectJ切面的驅動器 --> <aop:aspectj-autoproxy proxy-target-class="true"/><!-- 使用了@AspectJ注解的切面類 --> <bean class="com.xgj.aop.spring.advisor.aspectJ.function.args.ArgsAspect"/></beans>測試類:
package com.xgj.aop.spring.advisor.aspectJ.function.args;import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class ArgsAspectTest {private ApplicationContext ctx;@Testpublic void test() {ctx = new ClassPathXmlApplicationContext("classpath:com/xgj/aop/spring/advisor/aspectJ/function/args/conf-args.xml");UserService userService = ctx.getBean("userService", UserService.class);UserServiceExt userServiceExt = ctx.getBean("userServiceExt", UserServiceExt.class);User user = new User();ArtisanTT artisan = new ArtisanTT();// 織入橫切邏輯userService.addUser(user);// 織入橫切邏輯userService.modifyUser(user);// 織入橫切邏輯userService.delUser(user);System.out.println("================================");// 入參不是user,因此不會被織入橫切邏輯userService.addArtisanTT(artisan);userService.modifyArtisanTT(artisan);userService.delArtisanTT(artisan);System.out.println("================================");// 入參為user,因此也會被織入橫切邏輯userServiceExt.addUser(user);// 入參為user,因此也會被織入橫切邏輯userServiceExt.modifyUser(user);// 入參為user,因此也會被織入橫切邏輯userServiceExt.delUser(user);System.out.println("================================");// 入參不是user,因此不會被織入橫切邏輯userServiceExt.addArtisanTT(artisan);userServiceExt.modifyArtisanTT(artisan);userServiceExt.delArtisanTT(artisan);} }運行結果:
2018-01-04 09:19:50,614 INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@4a05bc0c: startup date [Thu Jan 04 09:19:50 CST 2018]; root of context hierarchy 2018-01-04 09:19:50,795 INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/aspectJ/function/args/conf-args.xml] some logic is here addUser com.xgj.aop.spring.advisor.aspectJ.function.args.User@657531ef some logic is here modifyUser com.xgj.aop.spring.advisor.aspectJ.function.args.User@657531ef some logic is here delUser com.xgj.aop.spring.advisor.aspectJ.function.args.User@657531ef ================================ addArtisanTT com.xgj.aop.spring.advisor.aspectJ.function.args.ArtisanTT@712175f2 modifyArtisanTT com.xgj.aop.spring.advisor.aspectJ.function.args.ArtisanTT@712175f2 delArtisanTT com.xgj.aop.spring.advisor.aspectJ.function.args.ArtisanTT@712175f2 ================================ some logic is here 入參為user的類 addUser com.xgj.aop.spring.advisor.aspectJ.function.args.User@657531ef some logic is here 入參為user的類 modifyUser com.xgj.aop.spring.advisor.aspectJ.function.args.User@657531ef some logic is here 入參為user的類 delUser com.xgj.aop.spring.advisor.aspectJ.function.args.User@657531ef ================================ addArtisanTT com.xgj.aop.spring.advisor.aspectJ.function.args.ArtisanTT@712175f2 modifyArtisanTT com.xgj.aop.spring.advisor.aspectJ.function.args.ArtisanTT@712175f2 delArtisanTT com.xgj.aop.spring.advisor.aspectJ.function.args.ArtisanTT@712175f2@args()
首先我們先自定義一個注解,用于測試用
package com.xgj.aop.spring.advisor.aspectJ.function.args.atargs;import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/*** * * @ClassName: Monitor* * @Description: 自定義注解 @Monitor* 更多信息請閱讀http://blog.csdn.net/yangshangwei/article/* details/77477840* * @author: Mr.Yang* * @date: 2017年9月1日 下午4:00:12*/@Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE, ElementType.METHOD }) @Documented public @interface Monitor {public boolean value() default true; }使用注解掃描的4個POJO
package com.xgj.aop.spring.advisor.aspectJ.function.args.atargs;import org.springframework.stereotype.Component;@Component public class T0 {} package com.xgj.aop.spring.advisor.aspectJ.function.args.atargs;import org.springframework.stereotype.Component;@Component public class T1 extends T0 {/*** * * @Title: fun* * @Description: 目標類方法,旨在這個方法中織入增強邏輯. 當注解標注在T2,方法的入參為T2或者T2的子孫類時,會織入增強* * @param t* * @return: void*/public void fun(T2 t) {System.out.println(t.getClass().getName() + " fun executed");} } package com.xgj.aop.spring.advisor.aspectJ.function.args.atargs;import org.springframework.stereotype.Component;@Monitor @Component public class T2 extends T1 {} package com.xgj.aop.spring.advisor.aspectJ.function.args.atargs;import org.springframework.stereotype.Component;@Component public class T3 extends T2 {}切面
package com.xgj.aop.spring.advisor.aspectJ.function.args.atargs;import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before;/*** * * @ClassName: AtArgsAspect* * @Description: 標注了@Aspect的切面* * @author: Mr.Yang* * @date: 2017年9月1日 下午4:21:14*/@Aspect public class AtArgsAspect {@Before("@args(com.xgj.aop.spring.advisor.aspectJ.function.args.atargs.Monitor)")public void crossCuttingCode() {System.out.println("前置增強 橫切邏輯織入 some logic is here ");} }配置文件:
<?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"xmlns:context="http://www.springframework.org/schema/context"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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- (1)聲明Context命名空間以及Schema文件 (2)掃描類包以及應用注解定義的bean --> <context:component-scan base-package="com.xgj.aop.spring.advisor.aspectJ.function.args.atargs"/><!-- 基于@AspectJ切面的驅動器 --> <aop:aspectj-autoproxy proxy-target-class="true"/><!-- 使用了@AspectJ注解的切面類 --> <bean class="com.xgj.aop.spring.advisor.aspectJ.function.args.atargs.AtArgsAspect"/></beans>測試類
package com.xgj.aop.spring.advisor.aspectJ.function.args.atargs;import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class AtArgsAspectTest {@Testpublic void test() {ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:com/xgj/aop/spring/advisor/aspectJ/function/args/atargs/conf-atargs.xml");T0 t0 = ctx.getBean("t0", T0.class);T1 t1 = ctx.getBean("t1", T1.class);T2 t2 = ctx.getBean("t2", T2.class);T3 t3 = ctx.getBean("t3", T3.class);// 因t1中的fun入參為t2,且注解標注在了T2類上,t3又是t2的子類,所以 下面兩個調用都會織入增強t1.fun(t2);t1.fun(t3);} }運行結果:
2017-09-04 17:43:44,302 INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@f4efcb0: startup date [Mon Sep 04 17:43:44 BOT 2017]; root of context hierarchy 2017-09-04 17:43:44,390 INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/aspectJ/function/args/atargs/conf-atargs.xml] 前置增強 橫切邏輯織入 some logic is here com.xgj.aop.spring.advisor.aspectJ.function.args.atargs.T2$$EnhancerBySpringCGLIB$$fcff1873 fun executed 前置增強 橫切邏輯織入 some logic is here com.xgj.aop.spring.advisor.aspectJ.function.args.atargs.T3$$EnhancerBySpringCGLIB$$109aa116 fun executed從運行結果看,正確的織入了橫切邏輯。
在類繼承樹中注解點低于入參類型點,則注解點所在類及其子孫類作為方法入參時,該方法匹配切點@args(M), 符合。
如果我們先取消掉T2上的@Monitor注解,然后把注解標注在T0上
如下:
package com.xgj.aop.spring.advisor.aspectJ.function.args.atargs;import org.springframework.stereotype.Component;@Monitor @Component public class T0 {}運行結果:
2017-09-04 17:56:31,858 INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1c057a1e: startup date [Mon Sep 04 17:56:31 BOT 2017]; root of context hierarchy 2017-09-04 17:56:31,970 INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/aspectJ/function/args/atargs/conf-atargs.xml] com.xgj.aop.spring.advisor.aspectJ.function.args.atargs.T2$$EnhancerBySpringCGLIB$$42855f4c fun executed com.xgj.aop.spring.advisor.aspectJ.function.args.atargs.T3$$EnhancerBySpringCGLIB$$5620e7ef fun executed因在繼承樹中注解點高于入參類型點,因此該目標方法不可能匹配到切點@args(M)。
總結
以上是生活随笔為你收集整理的Spring-AOP @AspectJ切点函数之args()和@args()的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java-工具类之发送邮件
- 下一篇: Java-Java5.0泛型解读