基于@Aspect的AOP配置

10 篇文章 0 订阅

1、Spring除了支持Schema方式配置AOP,还支持注解方式:使用@Aspect来配置

2、Spring默认不支持@Aspect风格的切面声明,通过如下配置开启@Aspect支持:

Java代码   收藏代码
  1. <aop:aspectj-autoproxy/>  

3、通过以上配置,Spring就能发现用@Aspect注解的切面内并把它应用到目标对象上。

4、定义一个切面:

Java代码   收藏代码
  1. @Aspect  
  2. public class AspectStyle {  
  3.   
  4.     @Before("execution(* com.sxit..*.*(..))")  
  5.     public void before(){  
  6.         System.out.println("方法执行前执行.....");  
  7.     }  
  8. }  

 5、后置返回通知:

Java代码   收藏代码
  1. @AfterReturning("execution(* com.sxit..*.*(..))")  
  2. public void afterReturning(){  
  3.         System.out.println("方法执行完执行.....");  
  4. }  

 6、后置异常通知:

Java代码   收藏代码
  1. @AfterThrowing("execution(* com.sxit..*.*(..))")  
  2. public void throwss(){  
  3.         System.out.println("方法异常时执行.....");  
  4. }  

 7、后置最终通知:

Java代码   收藏代码
  1. @After("execution(* com.sxit..*.*(..))")  
  2. public void after(){  
  3.         System.out.println("方法最后执行.....");  
  4. }  

 8、环绕通知:

Java代码   收藏代码
  1. @Around("execution(* com.sxit..*.*(..))")  
  2. public Object around(ProceedingJoinPoint pjp){  
  3.         System.out.println("方法环绕start.....");  
  4.         try {  
  5.             pjp.proceed();  
  6.         } catch (Throwable e) {  
  7.             e.printStackTrace();  
  8.         }  
  9.         System.out.println("方法环绕end.....");  
  10. }  

 9、按上面的每一个通知都要写一个定义,其实这部分可以抽出来,定义个一个公共的切入点。

Java代码   收藏代码
  1. package com.sxit;  
  2.   
  3. import org.aspectj.lang.ProceedingJoinPoint;  
  4. import org.aspectj.lang.annotation.After;  
  5. import org.aspectj.lang.annotation.AfterReturning;  
  6. import org.aspectj.lang.annotation.AfterThrowing;  
  7. import org.aspectj.lang.annotation.Around;  
  8. import org.aspectj.lang.annotation.Aspect;  
  9. import org.aspectj.lang.annotation.Before;  
  10. import org.aspectj.lang.annotation.Pointcut;  
  11.   
  12. @Aspect  
  13. public class AspectStyle {  
  14.       
  15.     @Pointcut("execution(* com.sxit..*.*(..))")  
  16.     public void init(){  
  17.           
  18.     }  
  19.   
  20.     @Before(value="init()")  
  21.     public void before(){  
  22.         System.out.println("方法执行前执行.....");  
  23.     }  
  24.       
  25.     @AfterReturning(value="init()")  
  26.     public void afterReturning(){  
  27.         System.out.println("方法执行完执行.....");  
  28.     }  
  29.       
  30.     @AfterThrowing(value="init()")  
  31.     public void throwss(){  
  32.         System.out.println("方法异常时执行.....");  
  33.     }  
  34.       
  35.     @After(value="init()")  
  36.     public void after(){  
  37.         System.out.println("方法最后执行.....");  
  38.     }  
  39.       
  40.     @Around(value="init()")  
  41.     public Object around(ProceedingJoinPoint pjp){  
  42.         System.out.println("方法环绕start.....");  
  43.         Object o = null;  
  44.         try {  
  45.             o = pjp.proceed();  
  46.         } catch (Throwable e) {  
  47.             e.printStackTrace();  
  48.         }  
  49.         System.out.println("方法环绕end.....");  
  50.         return o;  
  51.     }  
  52. }  

 10、打印信息:

Java代码   收藏代码
  1. 方法before前执行.....  
  2. 方法环绕start.....  
  3. 我看.....................  
  4. 方法after执行.....  
  5. 方法环绕end.....  
  6. 方法afterReurning执行.....  


Aspectj切入点语法定义


在使用spring框架配置AOP的时候,不管是通过XML配置文件还是注解的方式都需要定义pointcut"切入点"

例如定义切入点表达式 execution(* com.sample.service.impl..*.*(..))

execution()是最常用的切点函数,其语法如下所示:

 整个表达式可以分为五个部分:

 1、execution(): 表达式主体。

 2、第一个*号:表示返回类型,*号表示所有的类型。

 3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。

 4、第二个*号:表示类名,*号表示所有的类。

 5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。

 

 



AspectJ的Execution表达式

execution()

execution()是最常用的切点函数,其语法如下所示:

 

execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?)  除了返回类型模式、方法名模式和参数模式外,其它项都是可选的。与其直接讲解该方法的使用规则,还不如通过一个个具体的例子进行理解。下面,我们给出各种使用execution()函数实例。

 

1)通过方法签名定义切点

 execution(public * *(..))l

匹配所有目标类的public方法,但不匹配SmartSeller和protected voidshowGoods()方法。第一个*代表返回类型,第二个*代表方法名,而..代表任意入参的方法;

 

 execution(* *To(..))l

匹配目标类所有以To为后缀的方法。它匹配NaiveWaiter和NaughtyWaiter的greetTo()和serveTo()方法。第一个*代表返回类型,而*To代表任意以To为后缀的方法;

 

2)通过类定义切点

 execution(*com.baobaotao.Waiter.*(..))l

匹配Waiter接口的所有方法,它匹配NaiveWaiter和NaughtyWaiter类的greetTo()和serveTo()方法。第一个*代表返回任意类型,com.baobaotao.Waiter.*代表Waiter接口中的所有方法;

 

 execution(*com.baobaotao.Waiter+.*(..))l

匹配Waiter接口及其所有实现类的方法,它不但匹配NaiveWaiter和NaughtyWaiter类的greetTo()和serveTo()这两个Waiter接口定义的方法,同时还匹配NaiveWaiter#smile()和NaughtyWaiter#joke()这两个不在Waiter接口中定义的方法。

 

3)通过类包定义切点

在类名模式串中,“.*”表示包下的所有类,而“..*”表示包、子孙包下的所有类。

 execution(* com.baobaotao.*(..))l

匹配com.baobaotao包下所有类的所有方法;

 

 execution(* com.baobaotao..*(..))l

匹配com.baobaotao包、子孙包下所有类的所有方法,如com.baobaotao.dao,com.baobaotao.servier以及com.baobaotao.dao.user包下的所有类的所有方法都匹配。“..”出现在类名中时,后面必须跟“*”,表示包、子孙包下的所有类;

 

 execution(* com..*.*Dao.find*(..))l

匹配包名前缀为com的任何包下类名后缀为Dao的方法,方法名必须以find为前缀。如com.baobaotao.UserDao#findByUserId()、com.baobaotao.dao.ForumDao#findById()的方法都匹配切点。

 

4)通过方法入参定义切点

切点表达式中方法入参部分比较复杂,可以使用“*”和“..”通配符,其中“*”表示任意类型的参数,而“..”表示任意类型参数且参数个数不限。

 

 execution(* joke(String,int)))l

匹 配joke(String,int)方法,且joke()方法的第一个入参是String,第二个入参是int。它匹配NaughtyWaiter#joke(String,int)方法。如果方法中的入参类型是Java.lang包下的类,可以直接使用类名,否则必须使用全限定类名,如joke(java.util.List,int);

 

 execution(* joke(String,*)))l

匹 配目标类中的joke()方法,该方法第一个入参为String,第二个入参可以是任意类型,如joke(Strings1,String s2)和joke(String s1,double d2)都匹配,但joke(String s1,doubled2,String s3)则不匹配;

 

 execution(* joke(String,..)))l

匹配目标类中的joke()方法,该方法第 一个入参为String,后面可以有任意个入参且入参类型不限,如joke(Strings1)、joke(String s1,String s2)和joke(String s1,double d2,Strings3)都匹配。

 

 execution(* joke(Object+)))l

匹 配目标类中的joke()方法,方法拥有一个入参,且入参是Object类型或该类的子类。它匹配joke(Strings1)和joke(Client c)。如果我们定义的切点是execution(*joke(Object)),则只匹配joke(Object object)而不匹配joke(Stringcc)或joke(Client c)。

 

args()和@args()

args()函数的入参是类名,@args()函数的入参必须是注解类的类名。虽然args()允许在类名后使用+通配符后缀,但该通配符在此处没有意义:添加和不添加效果都一样。

 

1)args()

该函数接受一个类名,表示目标类方法入参对象按类型匹配于指定类时,切点匹配,如下面的例子:

args(com.baobaotao.Waiter)

表 示运行时入参是Waiter类型的方法,它和execution(**(com.baobaotao.Waiter))区别在于后者是针对类方法的签名而言的,而前者则针对运行时的入参类型而言。如args(com.baobaotao.Waiter)既匹配于addWaiter(Waiterwaiter),也匹配于addNaiveWaiter(NaiveWaiter naiveWaiter),而execution(**(com.baobaotao.Waiter))只匹配addWaiter(Waiterwaiter)方法;实际上,args(com.baobaotao.Waiter)等价于execution(**(com.baobaotao.Waiter+)),当然也等价于args(com.baobaotao.Waiter+)。

 

2)@args()

该函数接受一个注解类的类名,当方法的运行时入参对象标注发指定的注解时,方法匹配切点。

 

            





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值