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

  • @Before:前置通知,在方法执行之前执行;
  • @After:后置通知,在方法执行之后执行;
  • @AfterRunning:返回通知,在方法返回结果之后执行(因此该通知方法在方法抛出异常时,不能执行);
  • @AfterThrowing:异常通知,在方法抛出异常之后执行;
  • @Around:环绕通知,围绕着方法执行。

示例项目新建:

第一步:新建spring aop项目

第二步:添加spring-aop.xml Spring配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"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/context http://www.springframework.org/schema/context/spring-context-4.3.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"><!-- 配置自动扫描的包 --><context:component-scan base-package="com.dx.spring.beans.aop"></context:component-scan><!-- 配置是AspectJ注解起作用 :自动为匹配的类生成代理对象 --><aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

View Code

第三步:添加接口类IArithmeticCalculator.java,ArithmeticCalculatorImpl.java Spring组件

package com.dx.spring.beans.aop;/*** Description:Addition, subtraction, multiplication, and division*/
public interface IArithmeticCalculator {int add(int i, int j);int sub(int i, int j);int multi(int i, int j);int div(int i, int j);
}

View Code

package com.dx.spring.beans.aop;import org.springframework.stereotype.Component;@Component("arithmeticCalculator")
public class ArithmeticCalculatorImpl implements IArithmeticCalculator {@Overridepublic int add(int i, int j) {int result = i + j;return result;}@Overridepublic int sub(int i, int j) {int result = i - j;return result;}@Overridepublic int multi(int i, int j) {int result = i * j;return result;}@Overridepublic int div(int i, int j) {int result = i / j;return result;}
}

View Code

第四步:添加LoggingAspect.java切面

package com.dx.spring.beans.aop;import java.util.List;
import java.util.Arrays;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;//把这个类声明为一个切面:需要把该类放入到IOC容器中、再声明为一个切面。
@Aspect
@Component
public class LoggingAspect {// 在这里注册通知方法。
}

第五步:添加测试类Client.java

package com.dx.spring.beans.aop;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Client {public static void main(String[] args) {// 1:创建Spring的IOC容器;ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-aop.xml");// 2.从IOC容器中获取Bean的实例IArithmeticCalculator arithmeticCalculator = (IArithmeticCalculator) ctx.getBean("arithmeticCalculator");// 3.使用Bean
}
}

@Before:前置通知

在切面类LoggingAspect中添加前置通知:

    // 声明该方法为一个前置通知:在目标方法开始之前执行@Before("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))")public void beforeMethod(JoinPoint joinpoint) {String methodName = joinpoint.getSignature().getName();List<Object> args = Arrays.asList(joinpoint.getArgs());System.out.println("before method " + methodName + " with " + args);}

Client.java添加测试代码&执行测试:

        int result = arithmeticCalculator.add(1, 3);System.out.println(result);result = arithmeticCalculator.div(4, 1);System.out.println(result);

before method add with [1, 3]
before method div with [4, 0]

@After:后置通知

在切面类LoggingAspect中添加后置通知方法:

    // 声明该方法为一个后置通知:在目标方法结束之后执行(无论方法是否抛出异常)。// 但是因为当方法抛出异常时,不能返回值为null,因此这里无法获取到异常值。@After(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))")public void afterMethod(JoinPoint joinpoint) {String methodName = joinpoint.getSignature().getName();List<Object> args = Arrays.asList(joinpoint.getArgs());System.out.println("after method " + methodName);}

Client.java添加测试代码&执行测试:

        int result = arithmeticCalculator.add(1, 3);System.out.println(result);result = arithmeticCalculator.div(4, 0);System.out.println(result);

执行结果:

备注:从执行结果中我们可以看出,即使方法抛出异常,后置通知方法也会执行。

@AfterRunning:返回通知

修改切面类LoggingAspect,添加返回通知方法:

    /*** 声明该方法为一个返回通知:在目标方法返回结果时后执行(当方法抛出异常时,无法执行)。* 但是因为当方法抛出异常时,类似代码* {@code*   try                                                     <br/>*   {                                                       <br/>*        // before 前置通知                                  <br/>*        // do action method                                <br/>*        // after returning 返回通知,可以访问到方法的返回值     <br/>*   }*   catch(Exception e){*        e.printStackTrace();*        // after throwing 异常通知,可以访问到方法出现的异常*   }*   // after 后置通知,因为方法可以抛出异常,所以访问不到方法的返回值* }* */@AfterReturning(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))", returning = "result")public void afterReturningMethod(JoinPoint joinpoint, Object result) {String methodName = joinpoint.getSignature().getName();List<Object> args = Arrays.asList(joinpoint.getArgs());System.out.println("after method " + methodName + "  with returning " + (result == null ? "NULL" : result.toString()));}

注意:返回通知注解中,参数是多一个了returning参数,该参数定义通知方法接收返回值的别名。

在测试类Client.java中追加测试代码:

        int result = arithmeticCalculator.add(1, 3);System.out.println(result);result = arithmeticCalculator.div(4, 0);System.out.println(result);

@AfterThrowing:异常通知

修改切面类LoggingAspect,添加异常通知方法:

    /*** 定义一个异常通知函数:* 只有在方法抛出异常时,该方法才会执行,而且可以接受异常对象。* */@AfterThrowing(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))", throwing = "ex")public void afterThrowingMethod(JoinPoint joinpoint, Exception ex) {String methodName = joinpoint.getSignature().getName();List<Object> args = Arrays.asList(joinpoint.getArgs());System.out.println("after method " + methodName + " occurs exception: " + (ex == null ? "NULL" : ex.getMessage()));}

备注:只有在方法抛出异常时,异常通知方法才会执行,而且可以接受异常对象。

在测试类Client.java中追加测试代码:

        int result = arithmeticCalculator.add(1, 3);System.out.println(result);result = arithmeticCalculator.div(4, 0);System.out.println(result);

打印信息

@Around:环绕通知

环绕通知其他方式不同,它相当于代理对象使用时效果一样。可以在方法前、后、返回、异常打印信息。

我们先看代理方法打印信息时如何处理,之后再看环绕通知如何处理。

代理方法实现通知:

package com.dx.spring.beans.aop;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class ArithmeticCalculatorProxy implements InvocationHandler {private Object obj;public ArithmeticCalculatorProxy(Object obj) {this.obj = obj;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object object = null;try {// *** 前置通知,在方法执行之前执行System.out.println("before " + method);// 真实的调用方法操作object = method.invoke(obj, args);// *** 返回通知,在方法返回结果之后执行(因此该通知方法在方法抛出异常时,不能执行);System.out.println("before returning " + method);} catch (Exception ex) {ex.printStackTrace();// *** 异常通知,在方法抛出异常之后执行;System.out.println("before throwing " + method);throw ex;}// *** 后置通知,在方法执行之后执行;因为方法可以抛出异常,所以访问不到方法的返回值System.out.println("after " + method);return object;}
}

环绕通知:

修改切面类LoggingAspect,添加环绕通知:

package com.dx.spring.beans.aop;import java.util.List;
import java.util.Arrays;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;//把这个类声明为一个切面:需要把该类放入到IOC容器中、再声明为一个切面。
@Aspect
@Component
public class LoggingAspect {
//    // 声明该方法为一个前置通知:在目标方法开始之前执行
//    @Before("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))")
//    public void beforeMethod(JoinPoint joinpoint) {
//        String methodName = joinpoint.getSignature().getName();
//        List<Object> args = Arrays.asList(joinpoint.getArgs());
//        System.out.println("before method " + methodName + " with " + args);
//    }
//
//    // 声明该方法为一个后置通知:在目标方法结束之后执行(无论方法是否抛出异常)。
//    // 但是因为当方法抛出异常时,不能返回值为null,因此这里无法获取到异常值。
//    @After(value = "execution(public intcom.dx.spring.beans.aop.IArithmeticCalculator.*(int,int))")
//    public void afterMethod(JoinPoint joinpoint) {
//        String methodName = joinpoint.getSignature().getName();
//        List<Object> args = Arrays.asList(joinpoint.getArgs());
//        System.out.println("after method " + methodName);
//    }
//
//    /**
//     * 声明该方法为一个返回通知:在目标方法返回结果时后执行(当方法抛出异常时,无法执行)。 但是因为当方法抛出异常时,类似代码 {@code
//     * try <br/>
//     * { <br/>
//     * // before 前置通知 <br/>
//     * // do action method <br/>
//     * // after returning 返回通知,可以访问到方法的返回值 <br/>
//     * } catch(Exception e){ e.printStackTrace(); // after throwing
//     * 异常通知,可以访问到方法出现的异常 } // after 后置通知,因为方法可以抛出异常,所以访问不到方法的返回值 }
//     */
//    @AfterReturning(value = "execution(public intcom.dx.spring.beans.aop.IArithmeticCalculator.*(int,int))", returning = "result")
//    public void afterReturningMethod(JoinPoint joinpoint, Object result) {
//        String methodName = joinpoint.getSignature().getName();
//        List<Object> args = Arrays.asList(joinpoint.getArgs());
//        System.out.println(
//                "after method " + methodName + " with returning " + (result == null ? "NULL" : result.toString()));
//    }
//
//    /**
//     * 定义一个异常通知函数: 只有在方法跑吹异常时,该方法才会执行,而且可以接受异常对象。
//     */
//    @AfterThrowing(value = "execution(public intcom.dx.spring.beans.aop.IArithmeticCalculator.*(int,int))", throwing = "ex")
//    public void afterThrowingMethod(JoinPoint joinpoint, Exception ex) {
//        String methodName = joinpoint.getSignature().getName();
//        List<Object> args = Arrays.asList(joinpoint.getArgs());
//        System.out.println(
//                "after method " + methodName + " occurs exception: " + (ex == null ? "NULL" : ex.getMessage()));
//    }
@Around(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))")public Object aroundMethod(ProceedingJoinPoint pJoinPoint) throws Exception {String methodName = pJoinPoint.getSignature().getName();List<Object> args = Arrays.asList(pJoinPoint.getArgs());Object result = null;try {// 前置通知System.out.println("before method " + methodName + " with " + args);// 执行目标方法result = pJoinPoint.proceed();// 返回通知System.out.println("after method " + methodName + " returning " + result);} catch (Throwable ex) {// 异常通知System.out.println("after method " + methodName + " occurs exception: " + ex.getMessage());throw new Exception(ex);}// 后置通知System.out.println("after method " + methodName);return result;}
}

修改Client.java测试类,添加代码:

        int result = arithmeticCalculator.add(1, 3);System.out.println(result);result = arithmeticCalculator.div(4, 0);System.out.println(result);

执行结果

Spring(十八):Spring AOP(二):通知(前置、后置、返回、异常、环绕)相关推荐

  1. spring之aop(前置通知,后置通知,环绕通知,过滤通知,异常通知)

    1.AOP中关键性概念  连接点(Joinpoint):程序执行过程中明确的点,如方法的调用,或者异常的抛出 目标(Target):被通知(被代理)的对象 注1:完成具体的业务逻辑 通知(Advice ...

  2. spring之AOP(面向切面编程)和五大通知(前置通知、后置通知、异常通知、环绕通知、过滤通知)

    一.aop的介绍 1.AOP中关键性概念 : 连接点(Joinpoint):程序执行过程中明确的点,如方法的调用,或者异常的抛出. 目标(Target):被通知(被代理)的对象 注1:完成具体的业务逻 ...

  3. Spring AOP中的前置通知和后置通知详解

    不同版本的spring对AOP的支持有所不同,spring2.0之前,它主要针对不同类型的拦截器使用XML配置文件通过代理来实现.而spring2.0之后,它可以使用JDK5的注解来完成AOP的实现, ...

  4. 【二十八宿】又叫二十八舍或二十八星,是今人为观测日、

    [二十八宿]又叫二十八舍或二十八星,是今人为观测日.月.五星运行而划分的二十八个星区,用来解释日.月.五星运行所到的地位.每宿蕴含若干颗恒星.二十八宿的称号,自西向东排列为:东方苍龙七宿(角.亢kan ...

  5. AOP开发——在不修改源代码的前提下,对类里面的方法进行增强 : 前置 后置 环绕 异常||如何得到目标方法的参数和返回值

    AOP开发 @Transactionl 在不修改源代码的前提下,对类里面的方法进行增强 前置 后置 环绕 异常 创建项目前引入aop的包 <dependency>     <grou ...

  6. 手写Spring-第六章-让我访问!实现前置后置处理扩展功能

    前言 上一次我们实现了bean定义的自动化注册,这让我们的demo看起来已经很有Spring的那个味道了.但是扩展性还是差了一些.我们都知道,要写出高内聚,低耦合,富有扩展性的代码.那么如何增加扩展性 ...

  7. c 复杂的前置后置面试题_采摘后18小时直达货架,利农集团用后置仓“直连”生鲜电商...

    文 | 杨亚飞图片来源| pexels36氪获悉,日前,亚洲知名集约化无土水培果蔬种植企业利农集团完成新一轮数千万美元融资,投资方为海纳亚洲创投基金(SIG).本轮融资所得资金将继续使用于种植基地和产 ...

  8. spring3: Aspectj后置返回通知

    Aspectj后置返回通知 接口: package chapter1.server;public interface IHelloService2 {public int sayAfterReturn ...

  9. [凯圣王]碳水在身体内的去向/碳水前置后置的区别/碳水循环计划的简聊/训练前什么时间吃碳水

    碳水在身体内的去向/碳水前置后置的区别/碳水循环计划的简聊/训练前什么时间吃碳水 一.视频 二.碳水的种类 三.碳.蛋.脂 转换关系 四.碳水在身体中的储存数量 五.碳水什么时候补充 六.碳水循环饮食 ...

  10. 【Android RTMP】NV21 图像旋转处理 ( 快速搭建 RTMP 服务器 Shell 脚本 | 创建 RTMP 服务器镜像 | 浏览器观看直播 | 前置 / 后置摄像头图像旋转效果展示 )

    文章目录 安卓直播推流专栏博客总结 一. 编写快速搭建 RTMP 服务器 Shell 脚本 二. RTMP 快速搭建方法 三.创建阿里云 RTMP 服务器镜像 四.浏览器查看直播内容 五.前置 / 后 ...

最新文章

  1. UVA1388 Graveyard(思维、数学推理)
  2. 初学rpa的十大经典错误及解决办法_Python3之十大经典错误及其解决办法
  3. 本地化ASPXPivotGrid控件
  4. 牛客网_PAT乙级_10234有理数四则运算(20)【通过5/7:格式错误】
  5. mysql+rownumber的用法_mysql中如何实现row_number
  6. Halcon :畸变矫正与标定(2)
  7. .net winform panel 不刷新_【扫盲篇】visual studio2019(C#/.NET)安装教程
  8. 程序员惨遭辞退竟只因提了些代码修改意见?
  9. arm cpu的架构及分类说明
  10. JAVE 视音频转码
  11. 哔哩哔哩mac电脑版上线,来聊聊B站Mac版客户端初体验
  12. 学习浙江大学Photoshop设计精讲精练过程中的重难点及内容收获
  13. 小米3的卡槽,卡住了
  14. 4. hda设备中的pcm文件(第二部分)
  15. 【RuoYi-Vue-Plus】问题笔记 06 - p6spy 日志打印 SQL 时间格式化问题
  16. 学会这招,走哪都管用-如何在MacBook air上安装windows10环境下的所有系统
  17. 学习linux可以考虑做的岗位
  18. 每个程序猿都应该知道的网站,数量有点多,请点收藏慢慢查看
  19. R语言中文分词包jiebaR
  20. 清华大学交叉信息研究院和计算机系,清华大学交叉信息研究院和量子信息中心揭牌成立...

热门文章

  1. 三十而立,立的是什么?(r11笔记第70天)
  2. Eclipse下FatJar插件的安装与使用
  3. 生成allure测试报告时报错的解决方法
  4. JAVA SE 学习day_10:集合、聊天室练习最终版
  5. Kali Linux搜索软件包
  6. Andorid SQLite数据库开发基础教程(3)
  7. ​Unity 2D游戏开发教程之2D游戏的运行效果
  8. HealthKit开发快速入门教程之HealthKit开发概述简介
  9. 解耦 多态性 java_java多态
  10. matlab做交互作用图,MatlabMatlab工程应用案例精要.ppt