spring_AOP前置通知&后置通知&返回通知&环绕通知

Spring AOP

AspectJ:(Java社区里最完整最流行的AOP框架)

spring自身也有一套AOP框架,但相比较于AspectJ,更推荐AspectJ

在Spring2.0以上版本中,可以使用基于AspectJ注解基于XML配置的AOP。


基于AspectJ注解:

用AspectJ注解声明切面
要在Spring中声明AspectJ切面,只需要在IOC容器中将切面声明为Bean实例,当在Spring IOC容器中初始化AspectJ切面之后,
Spring IOC容器就会为为那些与AspectJ切面相匹配的Bean创建代理。

AspectJ注解中,切面只是 一个带有@AspectJ注解的Java类

通知是标注有某种注解的的简单的java方法

AspectJ支持5种类型的通知注解:

-@Before 前置通知,在目标方法执行之前执行
-@After:后置通知:在目标方法执行之后执行,无论是否发生异常
-@AfterReturning:返回通知,在目标方法返回结果之后执行
-@AfterThrowing:异常通知,在目标方法抛出异常之后通知。
-@Around 环绕通知,围绕着目标方法执行。

基于AspectJ注解添加前置通知步骤:

1)加入jar包

com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar

commons-logging-1.1.3.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar

2)在配置文件中加入aop和context的命名空间

xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"

3)基于注解的方式

   1.在配置文件里加入如下配置:

[html]  view plain  copy
  1. <!-- 配置自动扫描的包  -->  
  2. <context:component-scan base-package="com.wul.spring.aop.impl"></context:component-scan>  
  3.   
  4. <!-- 使AspectJ注解起作用:自动为匹配的类生成代理对象 -->  
  5. <aop:aspectj-autoproxy></aop:aspectj-autoproxy>  
(当Spring IOC 容器侦测到Bean配置文件中的<aop:aspectj-autoproxy>元素时,会自动与AspectJ切面匹配的Bean创建代理。)

  2.声明一个切面的类并把横切关注点代码抽象到切面的类中:

I.切面首先是一个IOC中的bean,即加入@Component注释
II.切面还需要加入@Aspect

  3.在类中声明各种通知
I.声明一个方法

II.在方法前加入@Before注解

III.利用方法签名编写AspectJ切入点表达式


关于方法签名编写的切点表达式:

1.execution ( *com.wul.spring.aop.impl.AtithmeticCalculator. *(..))
   匹配 ArithmeticCalculator 中声明的所有方法,
    第一个 * 代表任意修饰符及任意返回值第二个 * 代表任意方法..  匹配任意数量的参数
   若目标类与接口与该切面在同一个包中, 可以省略包名.

2.execution ( public * ArithmeticCalculator.*(..))
   匹配 ArithmeticCalculator 接口的 所有公有方法.

3.execution(* * , *()..)
       一个 *代表匹配任意修饰符及任意返回值 第二个 * 代表任意类的对象 , 第三个 *代表任意方法
   参数列表中的 ..  匹配任意数量的参数.

4.在 AspectJ 中, 切入点表达式可以通过操作符 &&, ||, ! 结合起来. 

5.可以在通知方法中声明一个类型为 JoinPoint 的参数. 然后就能访问链接细节. 如方法名称和参数值. 
    public void beforeMethod(JoinPoint joinPoint)

     方法名:String methodName = joinPoint.getSignature().getName();
     参数值:List<Object> args = Arrays.asList(joinPoint.getArgs());


前置通知:

[java]  view plain  copy
  1. //声明该方法是一个前置通知:在目标方法开始之前执行  
  2. /   @Before("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.add(int ,int))")  
  3. @Before("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int ,int))")  
  4. public void beforeMethod(JoinPoint joinPoint){  
  5.     String methodName = joinPoint.getSignature().getName();  
  6.     List<Object> args = Arrays.asList(joinPoint.getArgs());  
  7.     System.out.println("The method "+methodName +" begins with "+ args);  
  8. }  


后置通知:

[java]  view plain  copy
  1. //后置通知:在目标方法之后(无论是否发生异常),执行的通知,  
  2. //在后置通知中还不能访问目标方法执行的结果。执行结果须在返回通知中访问。  
  3. @After("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int ,int))")  
  4. public void afterMethod(JoinPoint joinPoint){  
  5.     String methodName = joinPoint.getSignature().getName();  
  6.     System.out.println("The method "+ methodName+" ends");  
  7.   
  8. }  

返回通知:

[java]  view plain  copy
  1. //返回通知:在目标方法正常结束执行后的通知  
  2. //返回通知是可以访问到目标方法的返回值的  
  3. @AfterReturning(value="execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))"  
  4.                 , returning = "result")  
  5. public void afterRunningMethod(JoinPoint joinPoint , Object result){  
  6.     String methodName = joinPoint.getSignature().getName();  
  7.     System.out.println("The method "+ methodName+" ends with the Result "+ result);  
  8. }  

异常通知:

[java]  view plain  copy
  1. //在目标方法出现异常时会执行的代码,  
  2. //可以访问到异常对象,且可以指定在出现特定异常时在执行通知代码  
  3. //如下面Exception ex,若是指定为NullpointerException ex就不会执行通知代码  
  4. @AfterThrowing(value="execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))"  
  5.                   , throwing="ex")  
  6. public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){  
  7.     String methodName = joinPoint.getSignature().getName();  
  8.     System.out.println("The method "+ methodName+"occurs exception:"+ex);  
  9. }  


前置,后置,异常通知在动态代理类中实现的话:

[java]  view plain  copy
  1. @Override  
  2. public Object invoke(Object proxy, Method method, Object[] args)  
  3.         throws Throwable {  
  4.     String methodName = method.getName();  
  5.     //日志  
  6.     System.out.println("The method "+methodName+" begin with "+Arrays.asList(args));  
  7.     //执行方法  
  8.     Object result = null;  
  9.       
  10.     try{  
  11.         //前置通知  
  12.          result = method.invoke(target, args);  
  13.         //返回通知,可以访问到方法的返回通知  
  14.     }catch(Exception e){  
  15.         e.printStackTrace();  
  16.         //异常通知:可以访问到方法出现的异常  
  17.     }  
  18.       
  19.     //后置通知:因为方法可能出错,所以访问不到方法的返回值。  
  20.       
  21.     //日志  
  22.     System.out.println("The method "+methodName + " ends with "+result);  
  23.     return result;  
  24. }  



环绕通知:(类似于动态代理的过程)

[java]  view plain  copy
  1. package com.wul.spring.aop.impl;  
  2.   
  3. import java.util.Arrays;  
  4. import java.util.List;  
  5.   
  6. import org.aspectj.lang.JoinPoint;  
  7. import org.aspectj.lang.ProceedingJoinPoint;  
  8. import org.aspectj.lang.annotation.After;  
  9. import org.aspectj.lang.annotation.AfterReturning;  
  10. import org.aspectj.lang.annotation.AfterThrowing;  
  11. import org.aspectj.lang.annotation.Around;  
  12. import org.aspectj.lang.annotation.Aspect;  
  13. import org.aspectj.lang.annotation.Before;  
  14. import org.springframework.stereotype.Component;  
  15.   
  16. //把这个类声明为一个切面:需要把该类放入到IOC容器中,再声明为一个切面  
  17. @Aspect  
  18. @Component  
  19. public class LogginAspect {  
  20.       
  21.     //声明该方法是一个前置通知:在目标方法开始之前执行  
  22. //  @Before("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.add(int ,int))")  
  23.     @Before("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int ,int))")  
  24.     public void beforeMethod(JoinPoint joinPoint){  
  25.         String methodName = joinPoint.getSignature().getName();  
  26.         List<Object> args = Arrays.asList(joinPoint.getArgs());  
  27.         System.out.println("The method "+methodName +" begins with "+ args);  
  28.     }  
  29.       
  30.     //后置通知:在目标方法之后(无论是否发生异常),执行的通知,  
  31.     //在后置通知中还不能访问目标方法执行的结果。执行结果须在返回通知中访问。  
  32.     @After("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int ,int))")  
  33.     public void afterMethod(JoinPoint joinPoint){  
  34.         String methodName = joinPoint.getSignature().getName();  
  35.         System.out.println("The method "+ methodName+" ends");  
  36.       
  37.     }  
  38.     //返回通知:在目标方法正常结束执行后的通知  
  39.     //返回通知是可以访问到目标方法的返回值的  
  40.     @AfterReturning(value="execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))"  
  41.                     , returning = "result")  
  42.     public void afterRunningMethod(JoinPoint joinPoint , Object result){  
  43.         String methodName = joinPoint.getSignature().getName();  
  44.         System.out.println("The method "+ methodName+" ends with the Result "+ result);  
  45.     }  
  46.       
  47.       
  48.     //在目标方法出现异常时会执行的代码,  
  49.     //可以访问到异常对象,且可以指定在出现特定异常时在执行通知代码  
  50.     //如下面Exception ex,若是指定为NullpointerException ex就不会执行通知代码  
  51.     @AfterThrowing(value="execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))"  
  52.                       , throwing="ex")  
  53.     public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){  
  54.         String methodName = joinPoint.getSignature().getName();  
  55.         System.out.println("The method "+ methodName+"occurs exception:"+ex);  
  56.     }  
  57.       
  58.     //坏绕通知:需要携带ProceedingJoinPoint类型的参数  
  59.     //环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法  
  60.     //且环绕通知必须有返回值,返回值即目标方法的返回值。  
  61.     @Around("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))")  
  62.     public Object aroundMethod(ProceedingJoinPoint pjd){  
  63.         Object result = null;  
  64.         String methodName = pjd.getSignature().getName();  
  65.         Object args = Arrays.asList(pjd.getArgs());  
  66.         //执行目标方法  
  67.         try {  
  68.             //前置通知  
  69.             System.out.println("Arround:The method "+methodName +" begins with "+ args);              
  70.             result = pjd.proceed();  
  71.             //后置通知  
  72.             System.out.println("Arround:The method "+ methodName+" ends");  
  73.         } catch (Throwable e) {  
  74.             e.printStackTrace();  
  75.             //异常通知  
  76.             System.out.println("Arround:The method "+ methodName+"occurs exception:"+e);  
  77.             //throw new RuntimeException(e);  
  78.             //不抛出异常的话,异常就被上面抓住,执行下去,返回result,result值为null,转换为int  
  79.         }  
  80.         //返回通知  
  81.         System.out.println("Arround:The method "+ methodName+" ends with the Result "+ result);  
  82.           
  83.         //return 100;  
  84.         return result;  
  85.     }  
  86.       
  87. }  


下面给出示例:



AtithmeticCalculator.java

[java]  view plain  copy
  1. package com.wul.spring.aop.impl;  
  2.   
  3. public interface AtithmeticCalculator {  
  4.       
  5.         int add(int i, int j);  
  6.         int sub(int i, int j);  
  7.         int mul(int i, int j);  
  8.         int div(int i, int j);  
  9.           
  10. }  

AtithmeticCalculatorImpl.java

[java]  view plain  copy
  1. package com.wul.spring.aop.impl;  
  2.   
  3. import org.springframework.stereotype.Component;  
  4.   
  5. @Component  
  6. public class AtithmeticCalculatorImpl implements AtithmeticCalculator {  
  7.   
  8.     @Override  
  9.     public int add(int i, int j) {  
  10.         int result = i + j;  
  11.         return result;  
  12.     }  
  13.   
  14.     @Override  
  15.     public int sub(int i, int j) {  
  16.         int result = i - j;  
  17.         return result;  
  18.     }  
  19.   
  20.     @Override  
  21.     public int mul(int i, int j) {  
  22.         int result = i * j;  
  23.         return result;  
  24.     }  
  25.   
  26.     @Override  
  27.     public int div(int i, int j) {  
  28.         int result = i / j;  
  29.         return result;  
  30.     }  
  31.   
  32. }  

LogginAspect.java

[java]  view plain  copy
  1. package com.wul.spring.aop.impl;  
  2.   
  3. import java.util.Arrays;  
  4. import java.util.List;  
  5.   
  6. import org.aspectj.lang.JoinPoint;  
  7. import org.aspectj.lang.ProceedingJoinPoint;  
  8. import org.aspectj.lang.annotation.After;  
  9. import org.aspectj.lang.annotation.AfterReturning;  
  10. import org.aspectj.lang.annotation.AfterThrowing;  
  11. import org.aspectj.lang.annotation.Around;  
  12. import org.aspectj.lang.annotation.Aspect;  
  13. import org.aspectj.lang.annotation.Before;  
  14. import org.springframework.stereotype.Component;  
  15.   
  16. //把这个类声明为一个切面:需要把该类放入到IOC容器中,再声明为一个切面  
  17. @Aspect  
  18. @Component  
  19. public class LogginAspect {  
  20.       
  21.     //声明该方法是一个前置通知:在目标方法开始之前执行  
  22. //  @Before("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.add(int ,int))")  
  23.     @Before("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int ,int))")  
  24.     public void beforeMethod(JoinPoint joinPoint){  
  25.         String methodName = joinPoint.getSignature().getName();  
  26.         List<Object> args = Arrays.asList(joinPoint.getArgs());  
  27.         System.out.println("The method "+methodName +" begins with "+ args);  
  28.     }  
  29.       
  30.     //后置通知:在目标方法之后(无论是否发生异常),执行的通知,  
  31.     //在后置通知中还不能访问目标方法执行的结果。执行结果须在返回通知中访问。  
  32.     @After("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int ,int))")  
  33.     public void afterMethod(JoinPoint joinPoint){  
  34.         String methodName = joinPoint.getSignature().getName();  
  35.         System.out.println("The method "+ methodName+" ends");  
  36.       
  37.     }  
  38.     //返回通知:在目标方法正常结束执行后的通知  
  39.     //返回通知是可以访问到目标方法的返回值的  
  40.     @AfterReturning(value="execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))"  
  41.                     , returning = "result")  
  42.     public void afterRunningMethod(JoinPoint joinPoint , Object result){  
  43.         String methodName = joinPoint.getSignature().getName();  
  44.         System.out.println("The method "+ methodName+" ends with the Result "+ result);  
  45.     }  
  46.       
  47.       
  48.     //在目标方法出现异常时会执行的代码,  
  49.     //可以访问到异常对象,且可以指定在出现特定异常时在执行通知代码  
  50.     //如下面Exception ex,若是指定为NullpointerException ex就不会执行通知代码  
  51.     @AfterThrowing(value="execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))"  
  52.                       , throwing="ex")  
  53.     public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){  
  54.         String methodName = joinPoint.getSignature().getName();  
  55.         System.out.println("The method "+ methodName+"occurs exception:"+ex);  
  56.     }  
  57.       
  58.     //坏绕通知:需要携带ProceedingJoinPoint类型的参数  
  59.     //环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法  
  60.     //且环绕通知必须有返回值,返回值即目标方法的返回值。  
  61.     @Around("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))")  
  62.     public Object aroundMethod(ProceedingJoinPoint pjd){  
  63.         Object result = null;  
  64.         String methodName = pjd.getSignature().getName();  
  65.         Object args = Arrays.asList(pjd.getArgs());  
  66.         //执行目标方法  
  67.         try {  
  68.             //前置通知  
  69.             System.out.println("Arround:The method "+methodName +" begins with "+ args);              
  70.             result = pjd.proceed();  
  71.             //后置通知  
  72.             System.out.println("Arround:The method "+ methodName+" ends");  
  73.         } catch (Throwable e) {  
  74.             e.printStackTrace();  
  75.             //异常通知  
  76.             System.out.println("Arround:The method "+ methodName+"occurs exception:"+e);  
  77.             //throw new RuntimeException(e);  
  78.             //不抛出异常的话,异常就被上面抓住,执行下去,返回result,result值为null,转换为int  
  79.         }  
  80.         //返回通知  
  81.         System.out.println("Arround:The method "+ methodName+" ends with the Result "+ result);  
  82.           
  83.         //return 100;  
  84.         return result;  
  85.     }  
  86.       
  87. }  

applicationContext.xml

[html]  view plain  copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xmlns:aop="http://www.springframework.org/schema/aop"  
  5.     xmlns:context="http://www.springframework.org/schema/context"  
  6.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
  7.         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd  
  8.         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">  
  9.   
  10.     <!-- 配置自动扫描的包  -->  
  11.     <context:component-scan base-package="com.wul.spring.aop.impl"></context:component-scan>  
  12.       
  13.     <!-- 使AspectJ注解起作用:自动为匹配的类生成代理对象 -->  
  14.     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>  
  15.   
  16. </beans>  

Main.java

[java]  view plain  copy
  1. package com.wul.spring.aop.impl;  
  2.   
  3. import org.springframework.context.ApplicationContext;  
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  5.   
  6. public class Main {  
  7.       
  8.     public static void main(String[] args) {  
  9.           
  10.         //1.创建Spring的IOC容器  
  11.         ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");  
  12.           
  13.         //2.从IOC容器中获取bean的实例  
  14.         AtithmeticCalculator arithmeticCalculator = ctx.getBean(AtithmeticCalculator.class);  
  15.           
  16.         //3.使用bean  
  17.         int result = arithmeticCalculator.add(3,6);  
  18.         System.out.println("result: "+result);  
  19.           
  20.         result = arithmeticCalculator.div(10,5);  
  21.         System.out.println("result: "+result);  
  22.           
  23.         result = arithmeticCalculator.div(10,0);  
  24.     }     
  25.       
  26. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值