文章目录

  • 一、概述
  • 二、通知的定义
    • 1. 前置通知
    • 2. 后置通知
    • 3. 环绕通知
    • 4. 最终通知
    • 5. 异常通知
  • 三、通知的参数
    • 1. 切入点
    • 2. 通知的参数传递
  • 四、通知的顺序
  • 五、附录
    • 1. 常用注解
    • 2. 示例代码

Spring 的 AOP 功能中一个关键概念是通知(Advice),与切点(Pointcut)表达式相关联在特定节点织入一些逻辑,Spring 提供了五种类型的通知。

理解 AOP 概念参阅:《Spring的AOP和动态代理》
配置 AOP 参阅:《Spring基于注解配置AOP》《Spring基于XML配置AOP》

一、概述

AOP 中的通知是基于连接点(Join point)业务逻辑的一种增强,Spring AOP 提供了下面五种通知类型:

  • Before advice(前置通知):连接点前面执行,不能终止后续流程,除非抛异常
  • After returning advice(后置通知):连接点正常返回时执行,有异常不执行
  • Around advice(环绕通知):围绕连接点前后执行,也能捕获异常处理
  • After advice(最终通知):连接点退出时执行,无论是正常退出还是异常退出
  • After throwing advice(异常通知):连接点方法抛出异常时执行

AOP 的连接点一般是指目标类的方法,五种通知类型执行的节点如下:

二、通知的定义

Spring AOP 可以基于 XML 方式和基于注解方式定义,只是写法不同,这里只使用注解的方式来讲解通知的详细用法。

1. 前置通知

@Aspect 切面类中使用 @Before 注解简单地定义一个前置通知。

@Aspect
@Component
public class DemoAspect {@Before("execution(* cn.codeartist.spring.aop.advice.*.*(..))")public void doBefore() {// 自定义逻辑}
}

2. 后置通知

方法正常返回,会执行后置通知,使用 @AfterReturning 注解定义后置通知。

@AfterReturning("execution(* cn.codeartist.spring.aop.advice.*.*(..))")
public void doAfterReturning() {// 自定义逻辑
}

注解的 returning 属性可以绑定目标方法返回值,用于在通知中获取目标方法执行完成后的返回结果。

@AfterReturning(pointcut = "pointcut()", returning = "retVal")
public void doAfterReturning(Object retVal) {// 自定义逻辑(通过参数绑定方法切入点方法的返回值)
}

当注解使用了 returning 属性时,切入点会增加返回值类型的限制,上面使用的 Object 类型可以匹配到所有返回值类型的目标方法。

例如下面的情况,后置通知的代码不会被执行:

// 目标方法
public String doService() {return "码匠公众号";
}// 后置通知定义
@AfterReturning(pointcut = "pointcut()", returning = "retVal")
public void doAfterReturning(Integer retVal) {// 目标方法返回值是String类型,结果参数绑定类型是Integer,该通知不会被执行
}

3. 环绕通知

环绕通知可以在方法执行的任何节点添加逻辑,它可以实现另外 4 种通知的功能。
如果需要以线程安全的方式在方法执行前后共享状态,可以使用环绕通知。
@Around 注解来定义环绕通知,需要使用 ProceedingJoinPoint 作为参数,来执行目标方法调用。

@Around("execution(* cn.codeartist.spring.aop.advice.*.*(..))")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {// 方法执行前逻辑Object retVal = joinPoint.proceed();// 方法执行后逻辑return retVal;
}

joinPoint.proceed() 会调用目标方法,或者是调用另一个切面。

虽然环绕通知可以实现另外几种通知的功能,但在使用中都能实现功能的情况下,优先使用其他通知方式。

4. 最终通知

最终通知在方法退出的时候执行,使用 @After 注解定义,最终通知在方法正常退出和抛出异常时都会执行,通常用于资源的释放。

@After("execution(* cn.codeartist.spring.aop.advice.*.*(..))")
public void doAfter() {// 自定义逻辑
}

5. 异常通知

方法抛出异常的时候会执行异常通知,使用 @AfterThrowing 定义异常通知。

@AfterThrowing("execution(* cn.codeartist.spring.aop.advice.*.*(..))")
public void doAfterThrowing() {// 自定义逻辑
}

注解的 throwing 属性用来绑定目标方法抛出的异常,用于在通知中获取目标方法抛出的异常实例。

@AfterThrowing(pointcut = "pointcut()", throwing = "ex")
public void doAfterThrowing(Throwable ex) {// 自定义逻辑(通过参数绑定方法切入点方法抛出的异常)
}

当注解使用了 throwing 属性时,切入点会增加异常类型的限制,上面使用的 Throwable 类型可以匹配到所有异常类型。

例如下面的情况,异常通知的代码不会被执行:

// 目标方法
public void doServiceThrow() {throw new RuntimeException("Test exception");
}// 异常通知定义
@AfterThrowing(pointcut = "pointcut()", throwing = "ex")
public void doAfterThrowing(NullPointerException ex) {// 目标方法抛出的是RuntimeException,参数绑定类型是NullPointerException,该通知不会被执行
}

三、通知的参数

在定义通知的方法签名上可以指定参数来绑定目标方法的一些信息(例如前面讲到的后置通知和异常通知)。

1. 切入点

在定义通知方法的时候,一般可以使用 JoinPoint 作为参数,环绕通知使用 ProceedingJoinPoint。常用接口方法如下:

JoinPoint

public interface JoinPoint {// 获取代理对象Object getThis();// 获取目标对象Object getTarget();// 获取连接点方法的参数Object[] getArgs();// 获取连接点方法的签名Signature getSignature();}

ProceedingJoinPoint

public interface ProceedingJoinPoint extends JoinPoint {// 执行下一个切面的通知或者目标方法public Object proceed() throws Throwable;// 执行下一个切面的通知或者目标方法(带参数)public Object proceed(Object[] args) throws Throwable;}

切面的切入点一般为方法,所以 Signature 可以转换为 MethodSignature 使用。

2. 通知的参数传递

通知的参数可以通过切点表达式 args 来指定,具体用法会在后面切点表达式详解中讲到。

@Before("pointcut() && args(name,..)")
public void doBefore(String name) {// 切点表达式增加参数匹配
}

args(name,..) 也会增加切入点的限制,目标方法的参数个数至少为一个,且第一个参数类型为 String

四、通知的顺序

Spring AOP 中一个目标类可以被多个切面切入,多个切面也可以切入一个目标类。
使用 @Order 注解来指定切面的优先级,来控制切面的执行顺序。
在注册切面 Bean 的时候指定 @Order,如下:

@Order(1)
@Aspect
@Component
public class FirstAspect {// ......
}

优先级高的切面先执行,通知执行的顺序如下:

可以得出:

  • 优先级高的切面,前置通知先执行
  • 优先级低的切面,后置通知先执行

Order 值越小,优先级越大。

Spring AOP 是基于动态代理的拦截器模式实现的,切面模型与拦截器模型相似,如下:

五、附录

1. 常用注解

注解 描述
@Aspect 定义切面类
@Before 定义前置通知
@AfterReturning 定义后置通知
@Around 定义环绕通知
@After 定义最终通知
@AfterThrowing 定义异常通知

2. 示例代码

Gitee 仓库:https://gitee.com/code_artist/spring
最新文章关注 CodeArtist 码匠公众号。

更多:Spring高效实践专栏

第14章-Spring AOP通知(Advice)详解相关推荐

  1. 跟着小马哥学系列之 Spring AOP(Advisor 详解)

    学好路更宽,钱多少加班. --小马哥 简介 大家好,我是小马哥成千上万粉丝中的一员!2019年8月有幸在叩丁狼教育举办的猿圈活动中知道有这么一位大咖,从此结下了不解之缘!此系列在多次学习极客时间< ...

  2. Spring AOP 与代理详解

    SpringBoot 系列教程 - 源码地址:https://github.com/laolunsi/spring-boot-examples 大家知道我现在还是一个 CRUD 崽,平时用 AOP 也 ...

  3. Spring AOP 功能使用详解

    前言 AOP 既熟悉又陌生,了解过 Spring 人的都知道 AOP 的概念,即面向切面编程,可以用来管理一些和主业务无关的周边业务,如日志记录,事务管理等:陌生是因为在工作中基本没有使用过,AOP ...

  4. 跟着小马哥学系列之 Spring AOP(AbstractAutoProxyCreator 详解)

    学成路更宽,吊打面试官. --小马哥 版本修订 2021.5.19:去除目录 简介 大家好,我是小马哥成千上万粉丝中的一员!2019年8月有幸在叩丁狼教育举办的猿圈活动中知道有这么一位大咖,从此结下了 ...

  5. spring事件通知机制详解

    优势 解耦 对同一种事件有多种处理方式 不干扰主线(main line) 起源 要讲spring的事件通知机制,就要先了解一下spring中的这些接口和抽象类: ApplicationEventPub ...

  6. Spring AOP切点表达式详解

    1. 简介 面向对象编程,也称为OOP(即Object Oriented Programming)最大的优点在于能够将业务模块进行封装,从而达到功能复用的目的.通过面向对象编程,不同的模板可以相互组装 ...

  7. Spring AOP实现原理详解之Cglib代理实现

    引入 我们在前文中已经介绍了SpringAOP的切面实现和创建动态代理的过程,那么动态代理是如何工作的呢?本文主要介绍Cglib动态代理的案例和SpringAOP实现的原理. 要了解动态代理是如何工作 ...

  8. Spring AOP 的proxy详解

    spring 提供了多种不同的方案实现对 bean 的 aop proxy, 包括 ProxyFactoryBean, 便利的 TransactionProxyFactoryBean 以及 AutoP ...

  9. Spring AOP之PointCut详解

    一.PointCut接口 /** Copyright 2002-2012 the original author or authors.** Licensed under the Apache Lic ...

最新文章

  1. 分类器评价与在R中的实现:收益图与提升图
  2. Fedora19 搭建LAMP环境
  3. 【转】EntityFramework使用Code First模式创建数据库控制生成单数形式的表名
  4. 【C语言】(数组方式)求n名同学的平均成绩
  5. Bootstrap 媒体列表
  6. 助力高校数字化建设,QQ小程序开发大赛正式启动
  7. Android 9 带着 AI 来了,为什么我们还停留在 6?
  8. 3D MAX插件大全介绍
  9. 『信息安全技术』 标准系列合集(467个)
  10. 嵌入式开发板硬件操作入门学习8——单片机的引脚功能(51单片机为例)
  11. 英文论文评审意见_英文论文审稿意见汇总
  12. python操作gif 图片拆分
  13. Win7盗版提示,屏幕右下角出现 Windows内部版本7601此Windows副本不是正版怎么办...
  14. php 工商银行公众号支付代码_微信支付 —— 公众号支付代码详解(1/7)
  15. 使用微信测试号进行wechat手动授权详细版
  16. Coder HDU - 4288
  17. 高等数学强化3:一元函数积分学 P积分
  18. Text组件新增内容通过tag_config设置前景色、背景色
  19. 运维工程师 常见的 trouble shooting 故障排错思路
  20. kali实施文件上传漏洞攻击:

热门文章

  1. 虚函数:多态的实现原理
  2. pair用法(给元素赋值)
  3. python打包flask项目exe
  4. unity 四元数和欧拉角的相互转换
  5. 【短信】谷歌4.4短信代码学习
  6. 第32篇 网络(二)HTTP
  7. Vulkan学习(十五): 总结
  8. 85-决策树解决回归问题
  9. 通过硬盘iso文件安装ubuntu
  10. 基于Jsp、Java、数据库、HTML实现网上投票系统(含文档和代码)Jsp课程设计