SpringAOP简介及实现(包含切面、切点、连接点和通知)

news2025/1/12 0:58:53

目录

1.什么是AOP、SpringAOP?

2.AOP的组成

3.SpringAOP的实现

4.切点的表达式


1.什么是AOP、SpringAOP?

在学习SpringAOP之前,我们得先了解一下什么是AOP。AOP是一种面向切面编程的思想。那什么是切面呢?它其实是对某一类事情的集中处理。比如,使用AOP的具体实现用来统一处理用户在访问网页时检查用户的登录状态的判断。在之前的学习中,我们是通过在每个需要处理用户请求的方法中都编写用户登录状态判断的代码,好在整体的方法数还比较少。


那如果方法很多呢?我们就需要在每一个每一个方法中编写相同逻辑代码判断用户的状态,我们写了如此多重复的代码反而是为了处理相同的一段逻辑,这是项目开发中的大忌,大大增强了我们程序的耦合性。而这一问题就可以使用AOP思想来进行处理,当用户发送请求时,我们将处理用户请求的不同方法中判断用户是否登录的逻辑视为一类事情,使用AOP思想的具体实现对这一类事情进行集中处理,这样我们只需要编写一遍代码,便能够在需要任何进行用户是否登录的逻辑判断的方法中进行判断与处理。上述的这种做法就是AOP思想的一种具体实现。

 


除此之外,使用SpringAOP还能够帮助我们进行:

  1. 统一日志记录
  2. 统一方法运行时间统计
  3. 统一的返回个事处理
  4. 统一的异常处理
  5. 事务的开启和提交
  6. ...

说了这么多,AOP和SpringAOP具体有什么联系呢?

不知道大家是否还记得,我们在Spring学习之初知道:IOC是一种控制反转思想,而DI就是这种思想的具体实现。类似的,AOP就是一种面向切面的思想或者说是集中处理的思想,而SpringAOP就是就针对这种切面思想的具体实现。既然SpringAOP的功能这么强大,那还不赶紧来学习一下它的使用和实现原理!

2.AOP的组成

在正式开始学习SpringAOP之前,我们有必要对AOP的组成进行理解,以便对我们接下来SpringAOP的具体实现和原理能有个充分的理解。AOP的组成大体共有以下四部分:

  1. 切面(Aspect)
    是切点和通知的结合,包括了横切逻辑的定义,也包括了逻辑点的定义。
  2. 切点(Pointcut)
    用来匹配连接点。
  3. 通知(Advice)
    切点的实现逻辑
  4. 连接点(Join Point)
    应用执行过程中能够插入切面的一个点

wc,看完懵逼,这是什么?看完定义想必肯定一头雾水。接下来,我们试着用通俗易懂的语言来描述一下AOP的这几个组成部分:

  1. 首先:切面
    在程序中,切面说白了其实就是一个类,这个类中包含了具体的拦截规则和拦截后的业务实现,是切点和通知的集合。
  2. 其次:切点。
    就是上面切面类中主动拦截时的条件。
  3. 然后:通知
    就是在拦截成功后,针对这一拦截做具体处理的业务代码。在AOP,通知又分为以下五类:
    1. 前置通知:在执行目标业务方法之前执行的方法
    2. 后置通知:在执行目标业务方法之后执行的方法
    3. 环绕通知:在执行目标业务方法之前和之后执行的方法
    4. 异常通知:目标方法抛出异常后执行的方法
    5. 返回通知:目标方法返回之后或者说执行结束后执行的方法
  4. 最后:连接点
    指的就是所有可能触发切面类中拦截规则即切点的所有请求的集合。

看完之后如果还不是特别清楚的话,我们接下来就来具体实现一个SpringAOP程序,来更好的理解上述AOP的相关组成。

3.SpringAOP的实现

接下来我们以拦截UserController类中的所有方法为例,来学习一下SpringAOP的具体实现步骤。


SpringAOP的具体实现分为以下三个步骤:

  1. 添加SpringAOP框架支持
  2. 定义切面类和切点
  3. 定义通知方法

SpringAOP中相关组成使用注解速查:

定义切面类@Aspect
定义切点@PointCut("切点表达式")
定义通知方法-前置通知@Before("针对切点的方法名")
定义通知方法-后置通知@After("针对切点的方法名")
定义通知方法-环绕通知@Around("针对切点的方法名")
定义通知方法-异常通知@AfterThrowing("针对切点的方法名")
定义通知方法-返回通知@AfterReturning("针对切点的方法名")

我们来在程序中具体实现,同时学习一下SPringAOP实现的细节及注意事项:

 

4.切点的表达式

AspectJ ⽀持三种通配符
* :匹配任意字符,只匹配⼀个元素(包,类,或⽅法,⽅法参数)
.. :匹配任意字符,可以匹配多个元素 ,在表示类时,必须和 * 联合使⽤。
+ :表示按照类型匹配指定类的所有类,必须跟在类名后⾯,如 com.cad.Car+ ,表示继承该类的 所有⼦类包括本身

切点表达式由切点函数组成,其中execution()为最常用的切点函数,切点定义的注解及其函数的语法如下:

@PointCut("execution(<修饰符> <返回类型> <包.类.方法(参数)> <异常>)")

【ps】:其中的修饰符和异常选项通常省略


😄例如,在我们上边的SpringAOP程序中:


 接下里我们来看看切点表达式中对应选项的一些常用写法:

😄对于修饰符

修饰符含义
*匹配目标类中被任意修饰符修饰的方法
public匹配目标类中被public修饰的方法
......

😄对于返回类型

返回类型含义
*匹配目标类中任意返回值类型的方法
String匹配目标类中字符串类型返回值的方法
void匹配目标类中无返回值的方法
......

😄对于包类型

包类型含义
com.shuai.demo固定包demo
com.shuai.demo.*.servicedemo二级包中任意的service包,例如:(com.shuai.demo.staff.service)
com.shuai.demo..demo包下的任意子包,包含自身
com.shuai.demo.*.service..demo二级包中任意的service包中的任意包,包含service自身
......

😄对于包中的类

类写法含义
包.UserController固定类Controller
包.*Controller以Controller结尾的类
包.User*以User开头的类
包.*包中的任意类
.....

😄 对于类中的方法

方法的写法含义
包.类.getUser固定方法getUser()
包.类.get*类中以add开头的方法
包.类.*Do类中以Do结尾的方法
包.类.*类中的任意方法
......

😄对于方法中的参数

方法中的参数写法含义
包.类.方法()类中的无参方法
包.类.方法(int)类中带一个Int类型参数的方法
包.类.方法(int,String)类中带一个int类型一个String类型的参数的方法
包.类.方法(..)类中任意参数的方法
......
 

写一些切点表达式来理解一下它的含义:

  • execution(* com.shuai.demo.User.*(..)) :匹配 User 类⾥的所有⽅法。
  • execution(* com.shuai.demo.User+.*(..)) :匹配User类的⼦类包括User类中的所有⽅法。
  • execution(* com.shuai.*.*(..)) :匹配 com.shuai包下的所有类的所有⽅法。
  • execution(* com.shuai..*.*(..)) :匹配 com.shuai包下、⼦孙包下所有类的所有⽅法。
  • execution(* com.shuai.demo.addUser(String, int)) :匹配 addUser ⽅法,且第⼀个参数类型是 String,第⼆个 参数类型是 int
  • ...

5.实例:SpringAOP实现统计方法执行时间

@Aspect    //告诉SpringAOP这是一个切面类
@Component //将其加入到Spring中进行管理
@Slf4j    //这里握住主要使用了其中的日志对象
public class UserAspect {

    @Pointcut("execution(String com.example.demo.controller.UserController.*(..)")
    public void getExecuteTime() {

    }

    /**
     * 统计UserController中的testAdvice方法的执行时间
     * @param joinPoint
     * @return  
     */
    @Around("getExecuteTime()")
    public Object timeAround(ProceedingJoinPoint joinPoint) {
        // 定义返回对象、得到方法需要的参数
        Object obj = null;
        Object[] args = joinPoint.getArgs();
        long startTime = System.currentTimeMillis();

        try {
            obj = joinPoint.proceed(args);
        } catch (Throwable e) {
            log.error("统计某方法执行耗时环绕通知出错", e);
        }

        // 获取执行的方法名
        long endTime = System.currentTimeMillis();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String methodName = signature.getDeclaringTypeName() + "." + signature.getName();

        // 打印耗时的信息
        log.info(methodName + "执行了: " + (endTime - startTime) + "ms");
        return obj;
    }
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/578213.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软件外包开发代码管理工具

软件代码规范是为了提高代码质量、可读性和可维护性而制定的一系列编程规则和约定。代码管理工具则是用于协助团队成员共享、跟踪和合并代码的工具。今天和大家分享这方面的知识&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&a…

定制底部footer bug:切换tab时position fixed会抖动

文章目录 bug描述position:fixed是啥&#xff1f;有啥用为什么切换tab的时候会抖动如何解决自定义一个InBody组件&#xff0c;将里面所有的元素放到body里面需要放到的底部的内容都放到这个组件里面 bug描述 在element admin里面定制了footer组件&#xff0c;每个页面也可还有…

离散数学_十章-图 ( 3 ):由旧图构造新图

&#x1f4f7;10.3 由旧图构造新图 概念1. 子图2. 真子图3. 导出的子图 旧图构造新图的方法1. 删除或增加图中的边2. 边的收缩3. 删除顶点 有时解决问题只需要图的一部分。 比如我们现在只关心大型计算机网络中涉及济南&#xff0c;广州&#xff0c;深圳的计算机中心&#xff0…

学习c语言中的几道习题(小有难度)!

有兴趣的朋友可以看着题目自己做做&#xff0c;最后在和答案对比&#xff01;相信能力会有所提升的。我现在只是刚刚开始学习c语言&#xff0c;如果有什么说的不对的地方&#xff0c;网路过的大佬&#xff0c;及时予以指正。多谢&#xff01; 1、函数判断闰年 实现函数判断yea…

chatgpt赋能python:Python行太长如何处理?

Python行太长如何处理&#xff1f; 介绍 Python 是一门强大的编程语言&#xff0c;易于学习和使用。它也因其可读性和简洁性而受到广泛赞誉。然而&#xff0c;在实际编写时&#xff0c;往往遇到了行太长的情况。 当一行代码在编辑器中撑满了整个屏幕&#xff0c;或者末尾的字…

【Redis入门篇】| Redis的Java客户端

目录 一&#xff1a; Redis的Java客户端 1. Jedis快速入门 2. Jedis连接池 3. SpringDataRedis快速入门 4. RedisSerializer配置 5. StringRedisTemplate 图书推荐 一&#xff1a; Redis的Java客户端 在Redis官网中提供了各种语言的客户端&#xff0c;地址&#xff1a;…

chatgpt赋能python:Python阶乘算法——快速、高效的算法实现!

Python阶乘算法 —— 快速、高效的算法实现&#xff01; Python作为一门高级编程语言&#xff0c;在众多领域都得到了广泛应用&#xff0c;尤其在算法领域更是拥有着举足轻重的地位。阶乘算法作为计算领域中的一种经典算法&#xff0c;也是Python中不可或缺的一部分。 什么是…

尚硅谷大数据hadoop教程_HDFS

P40 hdfs产生背景和定义 p41 优缺点 p42 组成 p43 文件块大小 p 44 45 shell命令 p46 api环境准备

单链表—C语言实现数据结构

本期带大家一起用C语言实现单链表&#x1f308;&#x1f308;&#x1f308; 文章目录 一、链表的概念&#x1f30e;二、链表中数据元素的构成&#x1f30e; &#x1f30d;三、链表的结构&#x1f30e; &#x1f30d; &#x1f30f;四、 单链表的实现✅✅二、接口的实现✅✅1.单…

SAP-MM-采购申请-价值特性

采购申请审批在维护价值特性时要注意是抬头价值还是行价值&#xff0c;要确定选择哪个&#xff0c;配置时对应配置。 1、创建价值特性CT04 字段名称&#xff1a;CEBAN-GSWRT&#xff0c;和CEBAN-GFWRT 抬头总价值&#xff1a;CEBAN-GFWRT&#xff1b;如果选择的是抬头审批&am…

WPF界面设计

目录 1.设计一个优美的注册界面1.实现效果2.代码展示 2.简易登录按钮设计1.实现效果2.代码展示 3.设计一个优美的注册登录界面&#xff08;连接数据库&#xff09;1.实现效果2.代码展示 4.设计一个简单的在线教育系统界面1.实现效果2.代码展示 5. 设计一个Dashboard1.实现效果2…

linux线程创建等待及退出总结

线程操作 线程操作分线程的创建&#xff0c;退出&#xff0c;等待 3 种 1. 线程创建 #include <pthread.h> int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg); // 返回&#xff1…

chatgpt赋能python:Python中的逆序数

Python中的逆序数 介绍逆序数 在数学中&#xff0c;逆序数指的是一个序列中逆序对的个数。逆序对指一个序列中的两个元素&#xff0c;其中较大的元素在前而较小的元素在后。例如&#xff0c;序列 [2, 4, 1, 3] 中逆序对的个数是 2&#xff1a;(2,1) 和 (4,1)。 逆序数常用于…

chatgpt赋能python:Python逆序遍历-解决问题的神奇方式

Python逆序遍历 - 解决问题的神奇方式 Python是一种简单易学的编程语言&#xff0c;依靠其强大的功能和可扩展性&#xff0c;已成为数据科学、人工智能和Web开发的首选语言之一。Python的核心优点之一是其非常方便的列表操作&#xff0c;而逆序遍历列表是Python的又一个实用而…

chatgpt赋能python:Python虚拟环境移植:为何以及如何

Python虚拟环境移植&#xff1a;为何以及如何 在Python项目开发过程中&#xff0c;管理项目依赖关系是一个很重要的问题。一个有效的解决方案是使用Python虚拟环境。虚拟环境是Python的一个工具&#xff0c;允许您在隔离的环境中管理Python包和依赖&#xff0c;从而避免不同开…

期末复习总结【MySQL】五种约束类型, 主键和外键的使用方式(重点)

文章目录 前言一、约束类型二、NOT NULL三、UNIQUE四、DEFAULT五、PRIMARY KEY(重点)1, 自增主键 六、FOREIGN KEY (重点)1, 插入数据2, 删除数据3, 关于外键约束下删除数据的思考 总结 前言 各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你: &#x1f4d5;…

chatgpt赋能python:Python词法分析:理解语言的起点

Python词法分析&#xff1a;理解语言的起点 在计算机科学中&#xff0c;词法分析&#xff08;也称为词法分析器&#xff09;是解析编程语言时的重要步骤之一。词法分析器将程序代码转换为由单词组成的序列&#xff08;称为标记或词法单元&#xff09;&#xff0c;为编译器和解…

chatgpt赋能python:Python转变为大写:学习如何使用Python中的str.upper()

Python 转变为大写&#xff1a;学习如何使用 Python 中的 str.upper() 作为一名有10年python编程经验的工程师&#xff0c;我可以肯定地说&#xff0c;Python 作为一门流行的编程语言&#xff0c;在全球范围内得到了广泛的应用。除了成为数据科学和机器学习的首选语言之外&…

设置ssh免密码登陆linux的配置步骤

概述 生成私钥文件 在客户端终端下输入以下命令 ssh-keygen -t rsa每次执行 ssh-keygen -t rsa 产生的私钥文件都会不同 如果文件"~/.ssh/id_rsa"存在&#xff0c;会提示是否覆盖该文件&#xff0c;此时可选择"n"不覆盖该文件而使用已有的id_rsa文件 如…

钉钉群通过短信转发器接收手机短信消息

1.短信转发器官网下载 下载地址 首发地址&#xff1a;https://github.com/pppscn/SmsForwarder/releases国内镜像&#xff1a;https://gitee.com/pp/SmsForwarder/releases网盘下载&#xff1a;https://wws.lanzoui.com/b025yl86h 访问密码&#xff1a;pppscn 使用文档 首发…