当前位置: 首页 > news >正文

Spring-AOP

目录

一:什么是AOP

二:AOP快速入门 

2.1导入AOP坐标

2.2定义dao接口和实现类

2.3定义通知类

 2.4在配置类中进行Spring注解包扫描和开启AOP功能

2.5定义测试类测试结果 

三:AOP工作流程 

四:AOP的切入点表达式 

4.1语法格式

4.2通配符 

五:AOP通知类型 

5.1前置通知 

5.2后置通知

5.3最终通知 

5.4异常通知

5.5环绕通知

六:总结 


一:什么是AOP

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

总的来说,AOP就是一编程规范,目的是在不改变方法源代码的基础上对方法进行功能增强。

二:AOP快速入门 

2.1导入AOP坐标

在pom.xml中导入aop坐标

<dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.3.31</version></dependency>
  <dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.7</version></dependency>

2.2定义dao接口和实现类

BookDao接口中: 

package com.lcyy.dao;public interface BookDao {void read();
}

实现类:注意要在BookDaoImpl方法上加入注解@Repository表示为交给Spring的一个组件

import com.lcyy.dao.BookDao;
import org.springframework.stereotype.Repository;@Repository
public class BookDaoImpl implements BookDao {@Overridepublic void read() {System.out.println("BookDao AOP 实现");}
}

2.3定义通知类

建立一个aop的包,在包下建立一个MyAdvice的通知类

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;@Component//放在普通类上,交给ioc容器管理
@Aspect//定义这个类为切面类
public class MyAdvice {//定义连接点@Pointcut("execution(void com.lcyy.dao.BookDao.read())")private void pc(){}//定义通知@Before("pc()")public void testAdvice(){System.out.println("执行前的时间毫秒值:");System.out.println(System.currentTimeMillis());}
}

 注意:

1.在MyAdvice类上要加入注解:@Aspect表示定义为一个切面类,@Component表示交给ioc容器管理。

2.@Pointcut注解要求配置在方法上方,("execution(void com.lcyy.dao.BookDao.read())")为切入点表达式,execution为关键字,

void为返回值 com.lcyy.dao.BookDao.read()为com.lcyy包下的dao包下的BookDao接口中的read()方法。

3.@Before("pc()") 其中@Before为前置通知,表示为在方法执行前执行。关于通知的几种类型,下面会详细讲解。其中 "pc()" 表示将连接点和通知捆绑起来,注意方法名必须相同。

 2.4在配置类中进行Spring注解包扫描和开启AOP功能

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration
@ComponentScan("com.lcyy")
@EnableAspectJAutoProxy//开启aop
public class SpringConfig {
}

其中注解 @EnableAspectJAutoProxy 表示开启AOP通知,交给IOC容器管理

2.5定义测试类测试结果 

import com.lcyy.config.SpringConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class BookDaoTest {public static void main(String[] args) {//获取容器ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);BookDao bookDao = ctx.getBean(BookDao.class);bookDao.read();}
}

测试结果:

三:AOP工作流程 

  1. Spring容器启动

  2. 读取所有切面配置中的切入点

  3. 初始化bean,判定bean对应的类中的方法是否匹配到任意切入点

    • 匹配失败,创建原始对象

    • 匹配成功,创建原始对象(目标对象)的代理对象

  4. 获取bean执行方法

    • 获取的bean是原始对象时,调用方法并执行,完成操作

    • 获取的bean是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作

验证AOP的代理对象,在刚才测试类中获取

import com.lcyy.config.SpringConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class BookDaoTest {public static void main(String[] args) {//获取容器ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);BookDao bookDao = ctx.getBean(BookDao.class);bookDao.read();System.out.println(bookDao.getClass());}
}

 测试结果:

其中:class com.sun.proxy.$Proxy19 就是为代理对象的类名 

四:AOP的切入点表达式 

4.1语法格式

描述方法一:执行com.lcyy.dao包下的BookDao接口中的无参数read方法

execution(void com.lcyy.dao.BookDao.read())

描述方法二:执行com.lcyy.dao包下的BookDaoImpl实现类中的无参数read方法

 execution(void com.lcyy.dao.BookDaoImpl.read())

切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数) 异常名)  

execution(public User com.itheima.service.UserService.findById(int)) 

其中:

  • 动作关键字:描述切入点的行为动作,例如execution表示执行到指定切入点

  • 访问修饰符:public,private等,可以省略

  • 返回值:写返回值类型

  • 包名:多级包使用点连接

  • 类/接口名:

  • 方法名:

  • 参数:直接写参数的类型,多个类型用逗号隔开

  • 异常名:方法定义中抛出指定异常,可以省略

4.2通配符 

(*):单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现

 (..):多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写

常用的通配符表达式为: 

@Pointcut("execution(* com.lcyy.dao.*.*(..)")

表示任意的访问修饰符 在com.lcyy.dao包下的任意类中的所有方法(..)表示可以有形参也可以没有形参。

五:AOP通知类型 

  • AOP通知共分为5种类型

    • 前置通知:在切入点方法执行之前执行

    • 后置通知:在切入点方法执行之后执行,无论切入点方法内部是否出现异常,后置通知都会执行。

    • 环绕通知(重点):手动调用切入点方法并对其进行增强的通知方式。

    • 最终通知:在切入点方法执行之后执行,如果切入点方法内部出现异常将不会执行。

    • 异常通知:在切入点方法执行之后执行,只有当切入点方法内部出现异常之后才执行。

5.1前置通知 

  • 名称:@Before

  • 类型:==方法注解==

  • 位置:通知方法定义上方

  • 作用:设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法前运行

  • 案例代码:

 //前置通知@Before("execution(void com.lcyy.dao.BookDao.write())")public void testAdvice2(){System.out.println("我是前置通知");}

5.2后置通知

  • 名称:@AfterReturning

  • 类型:==方法注解==

  • 位置:通知方法定义上方

  • 作用:设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法后运行

  • 案例代码:

    @AfterReturning("execution(void com.lcyy.dao.BookDao.write())")public void testAdvice4(){System.out.println("我是后置通知");}

5.3最终通知 

  • 名称:@After

  • 类型:==方法注解==

  • 位置:通知方法定义上方

  • 作用:设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法后运行

  • 案例代码:

@After("execution(void com.lcyy.dao.BookDao.write())")public void testAdvice3(){System.out.println("我是最终通知");}

5.4异常通知

  • 名称:@AfterThrowing

  • 类型:==方法注解==

  • 位置:通知方法定义上方

  • 作用:设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法运行抛出异常后执行

@AfterThrowing("execution(void com.lcyy.dao.BookDao.write())")public void testAdvice5(){System.out.println("我是异常通知");}

在以上四个通知后,我们在测试类中测试以上通知

 注意:书写了异常通知,却没有执行,是因为简单的代码实现没有异常。

测试异常通知:

在BookDaoImpl 的实现类中书写测试异常的代码

@Overridepublic void write() {System.out.println("BookDao AOP 实现");int a = 10/0;System.out.println("a = " + a);}

测试结果:

5.5环绕通知

  • 名称:@Around(重点,常用)

  • 类型:==方法注解==

  • 位置:通知方法定义上方

  • 作用:设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法前后运行

  • 案例代码:

  @Around("execution(void com.lcyy.dao.BookDao.jiyi())")public Object testJiyi(ProceedingJoinPoint PJ) throws Throwable {System.out.println("我时前置通知");Object Oj = PJ.proceed();System.out.println("我是后置通知");return Oj;}

 测试结果:

注意:

  1. 环绕通知方法形参必须是ProceedingJoinPoint,表示正在执行的连接点,使用该对象的proceed()方法表示对原始对象方法进行调用,返回值为原始对象方法的返回值。

  2. 环绕通知方法的返回值建议写成Object类型,用于将原始对象方法的返回值进行返回,哪里使用代理对象就返回到哪里。

六:总结 

AOP在spring中是一个很重要的概念,理解和运用AOP在以后的业务开发中有很重要的作用!

相关文章:

Spring-AOP

目录 一&#xff1a;什么是AOP 二&#xff1a;AOP快速入门 2.1导入AOP坐标 2.2定义dao接口和实现类 2.3定义通知类 2.4在配置类中进行Spring注解包扫描和开启AOP功能 2.5定义测试类测试结果 三&#xff1a;AOP工作流程 四&#xff1a;AOP的切入点表达式 4.1语法格…...

算法程序设计-快速排序

快速排序采用---分治策略 L |------x-------------| R 第一步确定分界点&#xff1a;q[l],q[(lr)/2],q[r]随机 第二步调整范围&#xff1a;L |--------<x|>x------------| R 第三步递归处理左右两端 两种做法&#xff1a; 第一种&#xff1a;暴力解决 另外定义两个…...

Jmeter用jdbc实现对数据库的操作

我们在用Jmeter进行数据库的操作时需要用到配置组件“JDBC Connection Configuration”&#xff0c;通过配置相应的驱动能够让我们通过Jmeter实现对数据库的增删改查&#xff0c;这里我用的mysql数据库一起来看下是怎么实现的吧。 1.驱动包安装 在安装驱动之前我们要先查看当前…...

Mac 上安装多版本的 JDK 且实现 自由切换

背景 当前电脑上已经安装了 jdk8; 现在再安装 jdk17。 期望 完成 jdk17 的安装&#xff0c;并且完成 环境变量 的配置&#xff0c;实现自由切换。 前置补充知识 jdk 的安装路径 可以通过查看以下目录中的内容&#xff0c;确认当前已经安装的 jdk 版本。 cd /Library/Java/Java…...

springboot如何发送邮件,java如何发送邮件随机码作为验证

maven <dependency><groupId>com.sun.mail</groupId><artifactId>javax.mail</artifactId><version>1.6.2</version></dependency> 然后java package com.metasoft.common.utils;import java.util.Properties;import javax.…...

使用QLoRA在自定义数据集上finetuning 大模型 LLAMA3 的数据比对分析

概述: 大型语言模型(LLM)展示了先进的功能和复杂的解决方案,使自然语言处理领域发生了革命性的变化。这些模型经过广泛的文本数据集训练,在文本生成、翻译、摘要和问答等任务中表现出色。尽管LLM具有强大的功能,但它可能并不总是与特定的任务或领域保持一致。 什么是LL…...

编译和链接(超详细)

✅博客主页:爆打维c-CSDN博客​​​​​​ &#x1f43e; &#x1f539;分享c语言知识及代码 一、编译和链接实例 假设我们有一个名为main.c的C语言源文件&#xff0c;它包含了一个简单的Hello World程序。我们可以使用gcc编译器对该源文件进行编译&#xff0c;生成一个可执行…...

Rust Turbofish 的由来

0x01 什么是 Turbofish 我们运行如下 Rust Snippet&#xff1a; fn main() {let numbers: Vec<i32> vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];let even_numbers numbers.into_iter().filter(|n| n % 2 0).collect();println!("{:?}", even_numbers); }不出意…...

2.外卖点餐系统(Java项目 springboot)

目录 0.系统的受众说明 1.系统功能设计 2.系统结构设计 3.数据库设计 3.1实体ER图 3.2数据表 4.系统实现 4.1用户功能模块 4.2管理员功能模块 4.3商家功能模块 4.4用户前台功能模块 4.5骑手功能模块 5.相关说明 新鲜运行起来的项目&#xff1a;如需要源码数据库…...

Universal Thresholdizer:将多种密码学原语门限化

参考文献&#xff1a; [LS90] Lapidot D, Shamir A. Publicly verifiable non-interactive zero-knowledge proofs[C]//Advances in Cryptology-CRYPTO’90: Proceedings 10. Springer Berlin Heidelberg, 1991: 353-365.[Shoup00] Shoup V. Practical threshold signatures[C…...

【UE5学习笔记】编辑及运行界面:关闭眼部识别(自动曝光)

自动曝光&#xff0c;也就是走进一个黑暗的环境&#xff0c;画面会逐渐变量&#xff0c;以模拟人眼进入黑暗空间时瞳孔放大&#xff0c;进光量增加的一种真实视觉感受&#xff1a; 制作过程中是否关闭自动曝光&#xff0c;取决于游戏的性质&#xff0c;但是个人认为&#xff0c…...

未来科技的前沿:深入探讨人工智能的进展、机器学习技术和未来趋势

文章目录 一、人工智能的定义和概述1. 人工智能的基本概念2. 人工智能的发展历史 二、技术深入&#xff1a;机器学习、深度学习和神经网络1. 机器学习2. 深度学习3. 神经网络 三、人工智能的主要目标和功能1. 自动化和效率提升2. 决策支持和风险管理3. 个性化服务和预测未来 本…...

3-qt综合实例-贪吃蛇的游戏程序

引言&#xff1a; 如题&#xff0c;本次实践课程主要讲解贪吃蛇游戏程序。 qt贪吃蛇项目内容&#xff1a; 一、功能需求 二、界面设计 各组件使用&#xff1a; 对象名 类 说明 Widget QWidge 主窗体 btnRank QPushButton 排行榜-按钮 groupBox QGroupBox 难…...

QGraphicsView实现简易地图12『平移与偏移』

前文链接&#xff1a;QGraphicsView实现简易地图11『指定层级-定位坐标』 提供地图平移与偏移功能。地图平移是指将地图的中心点更改为给定的点&#xff0c;即移动地图到指定位置。地图偏移是指将当前视口内的地图向上/下/左/右/进行微调&#xff0c;这里偏移视口宽/高的四分之…...

深入探索 Vue 中的 createVNode 与 resolveComponent

在 Vue 开发中&#xff0c;createVNode和resolveComponent是两个至关重要的工具&#xff0c;它们为我们提供了强大的能力来灵活地创建和操控组件。 一、首先&#xff0c;让我们深入了解一下createVNode。 这是一个用于创建虚拟节点的关键函数&#xff0c;通过它&#xff0c;我…...

【记录42】centos 7.6安装nginx教程详细教程

环境&#xff1a;腾讯云centos7.6 需求&#xff1a;安装nginx-1.24.0 1. 切入home文件 cd home 2. 创建nginx文件 mkdir nginx 3. 切入nginx文件 cd nginx 4. 下载nginx安装包 wget https://nginx.org/download/nginx-1.24.0.tar.gz 5. 解压安装包 tar -zxvf nginx-1.24.0.…...

C语言程序设计(不熟悉的点)

一、switch多路分支语句 二、条件表达式 三、循环 for循环&#xff1a; for循环的三个表达式不是必须的&#xff0c;第一个表达式之前声明过&#xff0c;可以不写&#xff0c;第三个表达式可以放在循环体里面&#xff1b;第二个表达式可以不写&#xff0c;为死循环。 空循环…...

DAO是什么?有什么用途?

DAO&#xff08;Decentralized Autonomous Organization&#xff0c;去中心化自治组织&#xff09;是一种基于区块链技术的组织形式&#xff0c;它没有中央管理层&#xff0c;而是通过智能合约和区块链上的代码来运作。DAO 的决策过程是透明的&#xff0c;通常由组织的成员通过…...

Socket学习记录

本次学习Socket的编程开发&#xff0c;该技术在一些通讯软件&#xff0c;比如说微信&#xff0c;QQ等有广泛应用。 网络结构 这些都是计算机网络中的内容&#xff0c;我们在这里简单回顾一下&#xff1a; UDP(User Datagram Protocol):用户数据报协议;TCP(Transmission Contr…...

黑马 - websocket搭建在线聊天室

这里写自定义目录标题 一、消息推送常见方式二、websocket 是什么&#xff1f;三、websocket api的介绍1、客户端 &#xff08;浏览器&#xff09;2、服务端api 四、实现在线聊天室1、需求2、聊天室流程分析3、消息格式4、代码实现 一、消息推送常见方式 1、轮训方式 2、SSE…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

Typeerror: cannot read properties of undefined (reading ‘XXX‘)

最近需要在离线机器上运行软件&#xff0c;所以得把软件用docker打包起来&#xff0c;大部分功能都没问题&#xff0c;出了一个奇怪的事情。同样的代码&#xff0c;在本机上用vscode可以运行起来&#xff0c;但是打包之后在docker里出现了问题。使用的是dialog组件&#xff0c;…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP&#xff0c;结果IP质量不佳&#xff0c;项目效率低下不说&#xff0c;还可能带来莫名的网络问题&#xff0c;是不是太闹心了&#xff1f;尤其是在面对海外专线IP时&#xff0c;到底怎么才能买到适合自己的呢&#xff1f;所以&#xff0c;挑IP绝对是个技…...

C#中的CLR属性、依赖属性与附加属性

CLR属性的主要特征 封装性&#xff1a; 隐藏字段的实现细节 提供对字段的受控访问 访问控制&#xff1a; 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性&#xff1a; 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑&#xff1a; 可以…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...