Spring AOP的介绍与实现

news2024/12/27 11:20:56

文章目录

  • Spring AOP
    • 1. Spring AOP概念
    • 2. Spring AOP的作用
    • 3.AOP的组成
    • 4. Spring AOP的实现
      • 4.1 添加Spring AOP依赖
      • 4.2 定义切面(创建切面类)
      • 4.3 定义切点(配置拦截规则)
        • 4.3.1 切点表达式语法
      • 4.4 定义通知的实现
    • 5. Spring AOP实现原理

Spring AOP

1. Spring AOP概念

AOP (Aspect Oriented Programming) :⾯向切⾯编程,是⼀种思想,它是对某⼀类事情的集中处理。

举个例子:
当我们进行用户登录权限的校验,在需要进行校验的页面中,我们都各⾃实现或调⽤⽤户验证的⽅法,有了 AOP 之后,我们只需要在某⼀处配置⼀下,需要登录校验的页面就可以自主实现,不再需要每个方法中都写相同的登录校验。

AOP与Spring AOP的关系和IoC和DI类似,AOP是一种思想,而Spring AOP是一个具体的框架对AOP的实现。

2. Spring AOP的作用

对于以上的登录校验例子来说,我们使用Spring AOP我们可以减少代码的重复,提高我们程序员开发的效率,在具体开发中它可以实现以下功能:

  1. 统一日志记录
  2. 统一方法执行时间统计
  3. 统一的返回格式设置
  4. 统一的异常处理
  5. 事务开启和提交
  6. 统一登录校验等

对于我们对象来说,AOP扩展了它的能力,在某个方面我们可以说AOP是OOP(面向对象编程)的补充和完善,它们都是一种思想。

3.AOP的组成

  • 切⾯(Aspect):切⾯(Aspect)由切点(Pointcut)和通知(Advice)组成,它既包含了横切逻辑的定义,也包括了连接点的定义。 在程序中就是一个处理某方面具体问题的类,类中包含很多方法,这些方法就是切点和通知。

  • 连接点(Join Point):应⽤执⾏过程中能够插⼊切⾯的⼀个点,这个点可以是方法调用时,抛出异常时或者修改字段时。切⾯代码可以利⽤这些点插⼊到应用的正常流程之中,并添加新的行为。它是可能会触发AOP的所有点(请求)。

  • 切点(Pointcut):切点是提供一组规则来匹配连接点,给满足规则的连接点添加通知。 切点就是用来进行主动拦截的规则(配置)然后触发AOP。

  • 通知(Advice):切面的工作被称为通知,定义了切⾯是什么,何时使用,描述了切⾯要完成的工作,还解决何时执行这个工作问题。也就是程序中被拦截请求触发的具体动作,在通知中的的具体业务代码。

通知的分类:使用注解可以实现

  • 前置通知:在执行目标方法之前执行的方法,@Before实现。比如我们要请求某页面要进行的登录检验相关方法,登录校验就是前置通知通过。请求页面的方法就是目标方法。
  • 后置通知:在执行目标方法之后执行的方法,通过@After实现。
  • 异常通知:在执行目标方法出现异常时执行的方法,通过@AfterThrowing实现。
  • 返回通知:目标方法执行了返回数据时(return)执行的通知,@AfterReturning实现。
  • 环绕通知:在目标方法执行的周期范围内(执行之前,执行中,执行后)都可以执行的。通过@Around实现。

4. Spring AOP的实现

4.1 添加Spring AOP依赖

首先创建一个Spring Boot项目,在创建过程中我们没有Spring AOP框架可选,需要在pom.xml文件中自己添加Spring AOP 依赖。
在这里插入图片描述

添加依赖,在Maven仓库中根据我们创建的spring boot项目添加以下依赖:
在这里插入图片描述

由于我使用的spring版本是2.7.13,所以我选用的版本也是2.7.13。

4.2 定义切面(创建切面类)

对于切面我使用的注解是@Component,让该类醉着框架启动。通过@Aspect表示该类是一个切面;

package com.example.demo_aop.component;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;

/**
 * @author zq
 * @date 2023-07-19 20:04
 */
@Component
@Aspect
public class UserAspect {
    
}

4.3 定义切点(配置拦截规则)

定义切点通过@Poincut注解,使用Aspect的表达式语法;该方法是空方法只起到表示作用,指向后面多个对应的通知。

  //定义切点,使用Aspect的表达式语法
//    表示拦截该UserController下所有方法
    @Pointcut("execution(* com.example.demo_aop.controller.UserController.*(..))")
    public void poincut(){

    }

4.3.1 切点表达式语法

切点表达式由切点函数组成,其中 execution() 是最常⽤的切点函数,⽤来匹配⽅法,语法为:

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

*号可以匹配任意字符,只匹配一个元素如包、类、方法、方法参数;…符号可以匹配任意字符,多个元素,在表示类时,需要与 星号联合使用;+号表示按照类型匹配指定类的所有类,必须跟在类名后面。如com.example.User+,就表示继承该类的所有子类和本身。

** 注意:**

  1. 修饰符和异常通常可以省略,返回值不能省略。
  2. 在我们上述代码中的表达式就省略了修饰符,用*号表示返回值类型。
  3. 返回值与包是两个东西所以加上了空格
  4. 在我们上述代码表达式省略了异常。括号中的点点表示匹配任意参数的方法。

4.4 定义通知的实现

以下实现前置通知和后置通知;注解中对应切点的方法名。

//    表示该通知针对该方法
//    前置通知
    @Before("pointcut()")
    public void beforeAdvice(){
        System.out.println("执行力前置通知");
    }
//    后置通知
    @After("pointcut()")
    public void AfterAdvice(){
        System.out.println("执行了后置通知");
    }

解释说明:我们不在切点中实现具体方法,是因为我们实现的方法有很多种,所以通过通知进行实现,它们具有1对多的关系。

在UserController类中创建方法检验AOP执行过程:

package com.example.demo_aop.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author zq
 * @date 2023-07-19 20:25
 */

@RequestMapping("/user")
@RestController
public class UserController {

    @RequestMapping("/hi")
    public String sayHi(String name){
        System.out.println("执行了sayHi方法");
        return "Hi" + name;
    }

    @RequestMapping("/hello")
    public String sayHello(String name){
        System.out.println("执行了sayHello方法");
        return "Hello" + name;
    }


}

如图当我们启动程序,访问http://localhost:8080/user/hi时,控制台输出结果符合AOP执行过程
在这里插入图片描述

同理我们可以在切面类中也实现环绕通知,指的注意的是我们在环绕通知中必须通过 object = joinPoint.proceed(); 才能执行目标方法,不然只是执行环绕通知 ;

//    环绕通知
    @Around("poincut()")
//    它必须有返回值返回给框架
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        Object object = null;
        System.out.println("进入环绕通知");
//        执行目标方法
        object = joinPoint.proceed();
        System.out.println("退出环绕通知");
        return object;
    }

执行结果如下:
在这里插入图片描述

5. Spring AOP实现原理

Spring AOP 是构建在动态代理基础上,因此 Spring 对 AOP 的支持局限于方法级别的拦截。Spring AOP ⽀持 JDK Proxy 和 CGLIB 方式实现动态代理。默认情况下,实现了接⼝的类,使⽤ AOP 会基于 JDK 生成代理类,没有实现接口的类,会基于 CGLIB 生成代理类。

也就是说我们本来要访问某个对象,但是我们Spring AOP构造了一个对应的代理类,我们访问时会通过代理类来访问我们的目标对象,不能直接访问

如图所示:对于我们以上代码来说我们本来是访问UserController类,但是我们不能直接访问了,而是通过访问代理类访问。
在这里插入图片描述

两种代理方式的区别:

  1. JDK 实现,要求被代理类必须实现接⼝,之后是通过 InvocationHandler 及 Proxy,在运行时动态的在内存中⽣成了代理类对象,该代理对象是通过实现同样接⼝来实现,只是该代理类是在运行期时,动态的织⼊统⼀的业务逻辑字节码来完成。
  2. CGLIB 实现,被代理类可以不实现接⼝,是通过继承被代理类,在运⾏时动态的生成代理类对象

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

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

相关文章

【Java】Mybatis使用Collection属性

前言 这篇文章实现一下不使用left join等连接关键字来实现Mybatis的联表查询功能。包括json类型数据映射到Java实体类中。 库表 父表db1_json 子表db1_json_attach&#xff0c;子表parent_id对应副本的id。 实体类 新建Db1JsonDTO数据传递对象实体。 Data public class Db…

GRE实验

题目参考&#xff1a; 实验步骤&#xff1a; 第一步&#xff1a;地址规划拓扑设计&#xff0c;配置IP地址 R1配置&#xff1a; <Huawei>system-view [Huawei]sy R1 [R1]int g 0/0/1 [R1-GigabitEthernet0/0/1]ip address 192.168.1.1 24 [R1-GigabitEthernet0/0/1]in…

【JavaEE】JavaEE进阶:框架的学习 - Spring的初步认识

JavaEE进阶首章 文章目录 【JavaEE】JavaEE进阶&#xff1a;框架的学习 - Spring的初步认识1. JavaEE初阶 与 JavaEE进阶 开发上的区别1.1 Servlet VS Spring Boot1.2 Spring Boot的 “hello world”代码演示1.2.1 Spring Boot项目的创建1.2.2 hello world1.2.3 发布 2. 框架的…

Python补充笔记2-函数

目录 一、函数​编辑 二、函数的创建和调用​编辑 三、函数的参数传递​编辑 四、参数传递的内存分析​编辑 五、函数的返回值​编辑 六、函数的参数定义 默认值参数 七、函数的参数总结​编辑 八、变量的作用域​编辑 九、递归函数 十、斐波那契数列 十一、知识点总结​编辑 …

A7二极管-ASEMI迷你封装整流管A7二极管

编辑&#xff1a;ll A7二极管-ASEMI迷你封装整流管A7二极管 型号&#xff1a;A7二极管 品牌&#xff1a;ASEMI 封装&#xff1a;SOD-123 正向电流&#xff1a;1A 反向耐压&#xff1a;1000V 芯片大小&#xff1a;60MIL 芯片个数&#xff1a;1 引脚数量&#xff1a;2 …

将监控摄像头的监控视频放在网页或APP中无插件播放

需求 1)将监控摄像头的监控视频集成到网页中&#xff0c;实现无插件播放&#xff0c;监控摄像头可以是海康、大华、TPLink等 2)将监控视频集成到业务平台中播放&#xff0c;包括网页、微信公众号、小程序、APP等形态 3)远程调取内网里的摄像头视频&#xff0c;实现远程监控 实现…

git rebase 合并提交

一. 合并提交步骤 git log --oneline 查看当前提交记录 git rebase -i HEAD~2 选择最后提交的2条记录进行合并进入编辑界面,将c865404的pick改为f, 表示向前合并也就是向cc5a54合并 编辑完之后:wq 保存并退出git rebase --continuegit push --force origin feature/v1.2 推送…

12. 一些开发中遇到的SQL问题

文章目录 一些开发中遇到的SQL问题1. sql报11090错误,原因可能是以下错误&#xff0c;在&#xff1f;占位符后有一个空格2. 占位符&#xff1f;的位置不能是表名&#xff0c;否则会无法进行预编译3. mysql中desc是关键字&#xff0c;如果字段名称为desc会报错4. 数据库中时间格…

【已解决】天翼电信宽带改桥模式,使用路由器ppoe拨号

运营商在给办理宽带时会默认给宽带设置成光猫ppoe拨号&#xff0c;路由器只需设置为dhcp获取ip&#xff0c;插入到光猫的lan口即可上网。但运营商的光猫路由性能有限&#xff0c;会影响到网络体验。而将光猫设置为桥模式&#xff0c;使用路由器拨号&#xff0c;可以实现路由器进…

vue树组件循环表格

最近做项目需要实现循环表格这个需求&#xff0c;其中实用到了循环组件&#xff0c;特此记录一下&#xff0c;这是需要实现的功能&#xff0c;如下图&#xff1a; vue中实现组件循环 父组件 <template><div><ul><li v-for"(item,index) in aside…

Zabbix 自动发现及注册

1、依次选择 Configuratio、Discovery、Create discovery rule&#xff08;配置、自动发现、创建发现规则&#xff09; 创建客户端发现规则 2、zabbix客户端安装 agent zabbix客户端一键安装脚本 脚本参考链接 #!/bin/bash #Zabbix-Agent 5.0Zabbix_Service192.168.63.20#安…

2023牛客暑期多校训练营1(D/H/J/K/M)

目录 D.Chocolate H.Matches J.Roulette K.Subdivision M.Water D.Chocolate 思路&#xff1a;当n1且m1时候先手必输&#xff0c;然后1*k&#xff08;k>2&#xff09;的情况下后手必输&#xff0c;因为先手可以选到只剩下一个格子。而在其它情况里先手第一步可以先选(…

使用对象解构赋值,将对象的某些属性赋值给另一个对象

在处理接口返回的数据时&#xff0c;我需要将接口返回的数据&#xff08;对象&#xff09;的某些属性用另一个对象进行接收&#xff0c;学习对象解构赋值之前&#xff0c;我一直使用的都是最笨的方法&#xff1a; this.formData.projectId res.data.projectId this.formData.…

奖牌数领跑是为何?解码长沙华中医卫科技中等职业学校的国防教育成功之道

近些年&#xff0c;越来越多的学生、家长、企业开始重新审视职业教育的价值。在产教融合的大背景下&#xff0c;职业教育已经成为了高新产业发展的人才引擎&#xff0c;职业教育的教学模式、软硬件配置乃至未来毕业生的就业情况&#xff0c;已完全变了模样。 实际上&#xff0…

Linux环境下的开发工具(yum、vim、gdb、make/Makefile)

目录 yum vim GDB调试 Makefile yum 在Linux系统上安装软件的方式有 下载到程序的源代码&#xff0c;自行进行编译&#xff0c;得到可执行程序。 获取rpm安装包&#xff0c;通过rpm命令进行安装。&#xff08;未解决软件的依赖关系&#xff09; 通过yum进行安装软件。&…

Android APP性能及专项测试

Android篇 1. 性能测试 Android性能测试分为两类&#xff1a; 1、一类为rom版本&#xff08;系统&#xff09;的性能测试 2、一类为应用app的性能测试Android的app性能测试包括的测试项比如&#xff1a; 1、资源消耗 2、内存泄露 3、电量功耗 4、耗时 5、网络流量消耗 6、移动…

evenloop事件循环机制

宏任务&#xff1a;script&#xff08;整体代码&#xff09;&#xff0c;setTimeout&#xff0c;setInterval&#xff0c;setImmediate&#xff0c;i/o&#xff0c;UIrendering 微任务&#xff1a;promise&#xff0c;async/await&#xff0c;Object.observe&#xff0c;Mutati…

Leetcode-每日一题【19.删除链表的倒数第N个结点】

题目 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;head [1], n 1输出&#xff1a;[] 示例 3&#x…

没有人能真正精通C++

任何说自己很懂C的人可能都是在夸大其词。 我想你可能已经注意到了&#xff0c;是的&#xff0c;今天的大多数程序员都在使用Python、Rust、Go或是其他新的编程语言。大部分人已经不再需要掌握C、C等古老的编程语言了&#xff0c;甚至很多程序员已经从手动编码开始向AI编码转型…

050、事务设计之Percolator事务模型

Percolator 背景 Bigtable: 大表打散每行到各个节点&#xff0c;每一行作为一个kv。解决的问题 一个事务涉及的行在多个节点&#xff0c;如何用单行对一个事务进行控制&#xff0c;实现原子性。 快照隔离级别&#xff08;snapshot &#xff09; 白色点&#xff1a;代表事务开始…