Spring AOP通知

本文介绍在Spring中使用AspectJ代替自带AOP,需导入相关Jar包,如com.springsource.net.sf.cglib - 2.20.jar等,并配置xml文件。还阐述了AspectJ支持的5种通知,包括前置和后置、返回和异常、环绕通知,同时给出相关运行结果及一些使用技巧,如设置异常通知条件、切面优先级等。

使用AspectJ代替Spring自带的Aop,在Spring中启用AspectJ注解支持需要以下导入Jar包:

com.springsource.net.sf.cglib-2.20.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

配置xml文件:

1 <!--组件扫描-->
2     <context:component-scan base-package="com.hxh.spring.aspectJ.annotation"/>
3     <!--基于注解使用AspectJ:主要作用是为切面中通知能作用到的目标类生成代理-->
4     <aop:aspectj-autoproxy/>

当Spring IOC容器检测到bean配置文件中的aop:aspectj-autoproxy时,会自动为AspectJ切面匹配的bean创建代理。

AspectJ支持的5种通知:

前置通知(@Before)<在方法执行之前执行>
后置通知(@After)<在方法执行之后执行>
环绕通知(@Around)<围绕着方法进行>
异常通知(@AfterThrowing)<在方法抛出异常之后执行>
返回通知(@AfterRunning)<围绕着方法执行> 

前置和后置通知

      /**
       * 日志切面
       */
      @Component //标识为一个组件,交给Spring的IOC管理
      @Aspect//标识为一个切面
      public class LoggingAspect {
          /**
           * 前置通知:在目标方法(连接点)执行之前执行。
           *
          */
         //找到目标方法(方法可能会重写,故要把参数写出来,前置通知只作用在add方法)
         @Before("execution(public int com.hxh.spring.aspectJ.annotation.mathCalculatorImpl.add(int,int))")
         public void beforeMethod(JoinPoint joinPoint){
         //方法前记录日志的通知
             Object argss[]=joinPoint.getArgs();
             String methodName=joinPoint.getSignature().getName();
             //数组不好打印,转换成集合打印:格式为[,,,]
             System.out.println("LoggingAspect--> The method "+methodName+"begin with "+ Arrays.asList(argss));
         }
         /**
          * 后置通知:在目标方法执行之后执行,不管目标方法有没有抛出异常,不能获取方法的结果
          * ..表示任意数量,任意类型的参数
          * 第一个*表示任意修饰符,任意返回值
          * 第二个*表示任意的类
          * 第三个*表示任意方法
          *
          * 连接点对象:JoinPoint
          */
         @After("execution(* com.hxh.spring.aspectJ.annotation.*.*(..))")
         public void afterMethod(JoinPoint joinPoint){
             //获取方法的名字:
             String methodName=joinPoint.getSignature().getName();
             System.out.println("LoggingAspect--> The method "+methodName+"ends");
         }
     }

Main.java

  public class Main {
      public static void main(String[] args) {
          ApplicationContext ctx=
                  new ClassPathXmlApplicationContext("spring-aspectJ_annotation.xml");
  
          mathCalculator ac=ctx.getBean("mathCalculatorImpl",mathCalculator.class);//mathCalculatorImpl实现类
          System.out.println(ac);
          System.out.println(ac.getClass().getName());
          int result=ac.add(1,2);
         System.out.println("result   :"+result);
 
 
     }
 }

运行结果

com.hxh.spring.aspectJ.annotation.mathCalculatorImpl@5c4b
com.sun.proxy.$Proxy8
LoggingAspect–> The method addbegin with [1, 2]
LoggingAspect–> The method addends
result :3

返回通知和异常通知

  /**
       * 返回通知:在目标方法正常执行结束后执行(也就是说有异常的时候不会执行)可以获取到方法的返回值。
       *returning="xx",xx必须跟你方法中的一个形参名字一样,这样就会把返回值给到xx。
       */
      @AfterReturning(value = "execution(* com.hxh.spring.aspectJ.annotation.*.*(..))",returning = "result")
      public void afterReturningMethod(JoinPoint joinPoint,Object result){
          String methodName=joinPoint.getSignature().getName();
          System.out.println("LoggingAspect--> The method "+methodName+"end with "+result);
      }
 
     /**
      * 异常通知:在目标方法抛出异常后执行
      *
      */
     @AfterThrowing(value = "execution(* com.hxh.spring.aspectJ.annotation.*.*(..))",throwing = "ex")
     public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){
         //方法的名字
         String methodName=joinPoint.getSignature().getName();
         System.out.println("LoggingAspect--> The method"+methodName+"occurs Exception: "+ex);
     }

Main.java

    result=ac.div(5,0);//by zero异常
    System.out.println("result   :"+result);

运行结果

LoggingAspect–> The method divends
Exception in thread “main” LoggingAspect–> The methoddivoccurs Exception: java.lang.ArithmeticException: / by zero

环绕通知(最强大)

  /**
       * 环绕通知:环绕着目标方法执行,可以理解为前置、后置、返回、异常通知的结合体,更像是动态代理的
       * 整个过程。
       *
       */
      @Around("execution(* com.hxh.spring.aspectJ.annotation.*.*(..))")
      public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint){
          //执行目标方法
          try {
             //前置
             Object result=proceedingJoinPoint.proceed();
             //返回
             return result;
         } catch (Throwable throwable) {
             //异常通知
             throwable.printStackTrace();
         }finally {
             //后置通知
         }
         return null;
     }

Tips:可以通过形参中异常的类型来设置抛出指定异常才会执行异常通知。比如说形参中写NullPointerException ex,只有
出现空指针异常才会执行异常通知。

ProceedingJoinPoin和joinPoint的关系 ProceedingJoinPoin extends joinPoint

Tips: @Order(1)//设置切面的优先级(int的最大值)2147483647,越小优先级越高 0x7fffffff 或者 Integer.MAX_VALUE可以表示int的最大值。二进制:01111111 11111111 11111111
11111111(高位是符号位,剩下的都是1)

@Pointcut("execution( com.hxh.spring.aspectJ.annotation..(…))") public void declarePointCut(){}
这个切入点表达式可以用一个方法名来代替。例如:@AfterReturning(value=“declarePointCut”,returning=“result”)
在不同的类中使用方法名得申明是哪个类下的切入点表达式。例如在ValidationAspect.java中使用LoggingAspect中定义的切入点表达式
declarePointCut(){} 声明为:ValidationAspect.declarePointCut*

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值