Spring-AOP概念及相关术语

AOP概念

  • 一、概述
    • 1、相关术语
    • 2、作用
  • 二、基于注解的AOP
    • 1、准备工作
    • 2、各种通知
    • 3、切入点表达式语法
    • 4、重用切入点表达式
    • 5、获取通知的相关信息
    • 6、切面的优先级


一、概述

回顾:
什么是面向对象
什么是AOP
AOP(Aspect Oriented Programming)是一种设计思想,是软件设计领域中的面向切面编程,它是面向对象编程的一种补充和完善,它以通过预编译方式和运行期动态代理方式实现在不修改源代码的情况下给程序动态统一添加额外功能的一种技术。

1、相关术语

①横切关注点
从每个方法中抽取出来的同一类非核心业务。在同一个项目中,我们可以使用多个横切关注点对相关方法进行多个不同方面的增强。这个概念不是语法层面天然存在的,而是根据附加功能的逻辑上的需要:有十个附加功能,就有十个横切关注点。
②通知
每一个横切关注点上要做的事情都需要写一个方法来实现,这样的方法就叫通知方法。
前置通知:在被代理的目标方法前执行
返回通知:在被代理的目标方法成功结束后执行(寿终正寝)
异常通知:在被代理的目标方法异常结束后执行(死于非命)
后置通知:在被代理的目标方法最终结束后执行(盖棺定论)
环绕通知:使用try…catch…finally结构围绕整个被代理的目标方法,包括上面四种通知对应的所
有位置.
在这里插入图片描述
③切面
封装通知方法的类。
④目标
被代理的目标对象。
⑤代理:向目标对象应用通知之后创建的代理对象。AOP中不需要我们手动的创建,封装的是代理模式。
⑥连接点:抽取横切关注点的位置
⑦切入点:定位连接点的方式

2、作用

简化代码:把方法中固定位置的重复的代码抽取出来,让被抽取的方法更专注于自己的核心功能,
提高内聚性。
代码增强:把特定的功能封装到切面类中,看哪里有需要,就往上套,被套用了切面逻辑的方法就
被切面给增强了。

二、基于注解的AOP

1、准备工作

①添加依赖

<!-- spring-aspects会帮我们传递过来aspectjweaver -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-aspects</artifactId>
	<version>5.3.1</version>
</dependency>

②准备被代理的目标资源
接口:

public interface Calculator {
int add(int i, int j);
int sub(int i, int j);
int mul(int i, int j);
int div(int i, int j);
}

实现类:

@Component
public class CalculatorImpl implements Calculator {
    @Override
    public int add(int i, int j) {
        int result = i + j;
        System.out.println("方法内部,result:"+result);
        return result;
    }

    @Override
    public int sub(int i, int j) {
        int result = i - j;
        System.out.println("方法内部,result:"+result);
        return result;
    }

    @Override
    public int mul(int i, int j) {
        int result = i * j;
        System.out.println("方法内部,result:"+result);
        return result;
    }

    @Override
    public int div(int i, int j) {
        int result = i / j;
        System.out.println("方法内部,result:"+result);
        return result;
    }
}

创建切面类并配置:

@Component
//将当前组件标识为切面
@Aspect
public class LoggerAspect {

    @Pointcut("execution(* org.example.spring.aop.annotation.CalculatorImpl.*(..))")
    public void pointCut(){}

    //@Before("execution(public int com.atguigu.spring.aop.annotation.CalculatorImpl.add(int, int))")
    //@Before("execution(* com.atguigu.spring.aop.annotation.CalculatorImpl.*(..))")
    @Before("pointCut()")
    public void beforeAdviceMethod(JoinPoint joinPoint) {
        //获取连接点所对应方法的签名信息
        Signature signature = joinPoint.getSignature();
        //获取连接点所对应方法的参数
        Object[] args = joinPoint.getArgs();
        System.out.println("LoggerAspect,方法:"+signature.getName()+",参数:"+ Arrays.toString(args));
    }

    @After("pointCut()")
    public void afterAdviceMethod(JoinPoint joinPoint){
        //获取连接点所对应方法的签名信息
        Signature signature = joinPoint.getSignature();
        System.out.println("LoggerAspect,方法:"+signature.getName()+",执行完毕");
    }

    /**
     * 在返回通知中若要获取目标对象方法的返回值
     * 只需要通过@AfterReturning注解的returning属性
     * 就可以将通知方法的某个参数指定为接收目标对象方法的返回值的参数
     */
    @AfterReturning(value = "pointCut()", returning = "result")
    public void afterReturningAdviceMethod(JoinPoint joinPoint, Object result){
        //获取连接点所对应方法的签名信息
        Signature signature = joinPoint.getSignature();
        System.out.println("LoggerAspect,方法:"+signature.getName()+",结果:"+result);
    }

    /**
     * 在异常通知中若要获取目标对象方法的异常
     * 只需要通过AfterThrowing注解的throwing属性
     * 就可以将通知方法的某个参数指定为接收目标对象方法出现的异常的参数
     */
    @AfterThrowing(value = "pointCut()", throwing = "ex")
    public void afterThrowingAdviceMethod(JoinPoint joinPoint, Throwable ex){
        //获取连接点所对应方法的签名信息
        Signature signature = joinPoint.getSignature();
        System.out.println("LoggerAspect,方法:"+signature.getName()+",异常:"+ex);
    }

    @Around("pointCut()")
    //环绕通知的方法的返回值一定要和目标对象方法的返回值一致
    public Object aroundAdviceMethod(ProceedingJoinPoint joinPoint){
        Object result = null;
        try {
            System.out.println("环绕通知-->前置通知");
            //表示目标对象方法的执行
            result = joinPoint.proceed();
            System.out.println("环绕通知-->返回通知");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("环绕通知-->异常通知");
        } finally {
            System.out.println("环绕通知-->后置通知");
        }
        return result;
    }

}

在Spring的配置文件中配置:

    <!--
        AOP的注意事项:
        切面类和目标类都需要交给IOC容器管理
        切面类必须通过@Aspect注解标识为一个切面
        在Spring的配置文件中设置<aop:aspectj-autoproxy />开启基于注解的AOP
    -->
    <context:component-scan base-package="org.example.spring.aop.annotation">
    </context:component-scan>

    <!--开启基于注解的AOP-->
    <aop:aspectj-autoproxy />

2、各种通知

前置通知:使用@Before注解标识,在被代理的目标方法前执行
返回通知:使用@AfterReturning注解标识,在被代理的目标方法成功结束后执行(寿终正寝)
异常通知:使用@AfterThrowing注解标识,在被代理的目标方法异常结束后执行(死于非命)
后置通知:使用@After注解标识,在被代理的目标方法最终结束后执行(盖棺定论)
环绕通知:使用@Around注解标识,使用try…catch…finally结构围绕整个被代理的目标方法,包
括上面四种通知对应的所有位置
各种通知的执行顺序:
Spring版本5.3.x以前:
前置通知
目标操作
后置通知
返回通知或异常通知
Spring版本5.3.x以后:
前置通知
目标操作
返回通知或异常通知
后置通知

3、切入点表达式语法

语法细节

  • 用*号代替“权限修饰符”和“返回值”部分表示“权限修饰符”和“返回值”不限
  • 在包名的部分,一个“*”号只能代表包的层次结构中的一层,表示这一层是任意的。
    • 例如:*.Hello匹配com.Hello,不匹配com.spring.Hello
  • 在包名的部分,使用“*…”表示包名任意、包的层次深度任意
  • 在类名的部分,类名部分整体用*号代替,表示类名任意
  • 在类名的部分,可以使用*号代替类名的一部分
    • 例如:*Service匹配所有名称以Service结尾的类或接口
  • 在方法名部分,可以使用*号表示方法名任意
  • 在方法名部分,可以使用*号代替方法名的一部分
    • 例如:*Operation匹配所有方法名以Operation结尾的方法
  • 在方法参数列表部分,使用(…)表示参数列表任意
  • 在方法参数列表部分,使用(int,…)表示参数列表以一个int类型的参数开头
  • 在方法参数列表部分,基本数据类型和对应的包装类型是不一样的
    • 切入点表达式中使用 int 和实际方法中 Integer 是不匹配的
  • 在方法返回值部分,如果想要明确指定一个返回值类型,那么必须同时写明权限修饰符
    • 例如:execution(public int …Service.*(…, int)) 正确
    • 例如:execution(* int …Service.*(…, int)) 错误
      在这里插入图片描述
      举例:CalculatorImpl类下的具有任意参数的任意方法
  @Pointcut("execution(* org.example.spring.aop.annotation.CalculatorImpl.*(..))")

4、重用切入点表达式

①声明

    @Pointcut("execution(* org.example.spring.aop.annotation.CalculatorImpl.*(..))")
    public void pointCut(){}

②在同一个切面中使用

@Before("pointCut()")
public void beforeMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
String args = Arrays.toString(joinPoint.getArgs());
System.out.println("Logger-->前置通知,方法名:"+methodName+",参数:"+args);
}

③在不同切面中使用

@Before("org.example.spring.aop.annotation.LoggerAspect.pointCut()")
public void beforeMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
String args = Arrays.toString(joinPoint.getArgs());
System.out.println("Logger-->前置通知,方法名:"+methodName+",参数:"+args);
}

5、获取通知的相关信息

①获取连接点信息

    @Before("pointCut()")
    public void beforeAdviceMethod(JoinPoint joinPoint) {
        //获取连接点所对应方法的签名信息
        Signature signature = joinPoint.getSignature();
        //获取连接点所对应方法的参数
        Object[] args = joinPoint.getArgs();
        System.out.println("LoggerAspect,方法:"+signature.getName()+",参数:"+ Arrays.toString(args));
    }

②获取目标方法的返回值
@AfterReturning中的属性returning,用来将通知方法的某个形参,接收目标方法的返回值

    /**
     * 在返回通知中若要获取目标对象方法的返回值
     * 只需要通过@AfterReturning注解的returning属性
     * 就可以将通知方法的某个参数指定为接收目标对象方法的返回值的参数
     */
    @AfterReturning(value = "pointCut()", returning = "result")
    public void afterReturningAdviceMethod(JoinPoint joinPoint, Object result){
        //获取连接点所对应方法的签名信息
        Signature signature = joinPoint.getSignature();
        System.out.println("LoggerAspect,方法:"+signature.getName()+",结果:"+result);
    }

③获取目标方法的异常
@AfterThrowing中的属性throwing,用来将通知方法的某个形参,接收目标方法的异常

    /**
     * 在异常通知中若要获取目标对象方法的异常
     * 只需要通过AfterThrowing注解的throwing属性
     * 就可以将通知方法的某个参数指定为接收目标对象方法出现的异常的参数
     */
    @AfterThrowing(value = "pointCut()", throwing = "ex")
    public void afterThrowingAdviceMethod(JoinPoint joinPoint, Throwable ex){
        //获取连接点所对应方法的签名信息
        Signature signature = joinPoint.getSignature();
        System.out.println("LoggerAspect,方法:"+signature.getName()+",异常:"+ex);
    }

环绕通知

    @Around("pointCut()")
    //环绕通知的方法的返回值一定要和目标对象方法的返回值一致
    public Object aroundAdviceMethod(ProceedingJoinPoint joinPoint){
        Object result = null;
        try {
            System.out.println("环绕通知-->前置通知");
            //表示目标对象方法的执行
            result = joinPoint.proceed();
            System.out.println("环绕通知-->返回通知");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("环绕通知-->异常通知");
        } finally {
            System.out.println("环绕通知-->后置通知");
        }
        return result;
    }

6、切面的优先级

  • 相同目标方法上同时存在多个切面时,切面的优先级控制切面的内外嵌套顺序。
    • 优先级高的切面:外面
    • 优先级低的切面:里面
  • 使用@Order注解可以控制切面的优先级:
    • @Order(较小的数):优先级高
    • @Order(较大的数):优先级低
      在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Go语言标准输入

文章目录 Go语言标准输入函数使用 Go语言标准输入 函数 Scan // 使用stdin读取内容&#xff0c;读取的内容以空白&#xff08;换行也属于空白&#xff09;分隔&#xff0c;赋值给函数参数。返回读取的个数和错误 func Scan(a ...interface{}) (n int, err error)Scanf // 和…

深度学习:激活函数曲线总结

深度学习&#xff1a;激活函数曲线总结 在深度学习中有很多时候需要利用激活函数进行非线性处理&#xff0c;在搭建网路的时候也是非常重要的&#xff0c;为了更好的理解不同的激活函数的区别和差异&#xff0c;在这里做一个简单的总结&#xff0c;在pytorch中常用的激活函数的…

智慧矿山系统中的猴车安全监测与识别

智慧矿山是近年来兴起的一种采用人工智能&#xff08;AI&#xff09;技术的矿山管理方式&#xff0c;它通过利用智能传感设备和先进算法来实现对矿山环境和设备进行监测和管理&#xff0c;从而提高矿山的安全性和效率。在智慧矿山的AI算法系列中&#xff0c;猴车不安全行为识别…

Web入门笔记

Web入门笔记 HTTP协议 超文本传输协议 规定了浏览器和服务器之间数据传输的规则&#xff0c;请问数据和响应数据的格式 基于TCP请求-响应模式一次请求对应一次响应无状态的协议 请问数据格式 浏览器版本&#xff1a;解决浏览器兼容问题。GET请求体&#xff1a;存放请求参数…

FOC系列(二)----继续学习DRV8301芯片

一、 程序框图 跟随上篇博客咱们继续往下看&#xff0c;下面是芯片内部的程序框图&#xff1a; 1.1 BUCK电路 1.2 内部各电源 1.3 SPI通信、栅极驱动器和时序控制器 1.4 MOSFET驱动电路 1.5 电流采样放大电路 数据手册只是给出了这一部分框图&#xff0c;但是没有更加详细的介…

Affinity Photo 2.2.1 高端专业Mac PS修图软件

Affinity Photo Mac中文版是一款面向专业摄影师和其他视觉艺术家的专业图像处理软件&#xff0c;拥有众多专业高端功能&#xff0c;如Raw处理、PSD导入和导出、16位通道的编辑和ICC色彩管理以及兼容大量图片格式。是现在最快、最顺、最精准的专业修图软件。Affinity Photo Mac是…

华媒舍:日韩媒体发稿推广中8个关键因素帮助你实现突破

在当今经济全球化的时代背景下&#xff0c;日韩地域媒体影响力日益提高。对于需要在这一地区开展发稿推广的人来讲&#xff0c;掌握适度的思路和流程是十分重要的。下面我们就为大家介绍8个关键因素&#xff0c;以帮助你在日韩地域媒体发稿推广中实现突破。 1.科学研究行业在逐…

UE5使用Dash插件实现程序化地形场景制作

目录 0 dash下载后激活 1 初步使用 2 导入bridge的资产路径 3 练习成果 4 参考链接 0 dash下载后激活 1 初步使用 Dash插件点击蓝色的A&#xff0c;可以使用。 通过输入不同提示命令&#xff0c;来激活不同的功能。 2 导入bridge的资产路径 这里需要注意是UAsserts…

粤嵌实训医疗项目--day04(Vue + SpringBoot)

往期回顾 粤嵌实训医疗项目--day03&#xff08;Vue SpringBoot&#xff09;-CSDN博客粤嵌实训医疗项目day02&#xff08;Vue SpringBoot&#xff09;-CSDN博客粤嵌实训医疗项目--day01&#xff08;VueSpringBoot&#xff09;-CSDN博客 目录 一、用户详细信息查询 (查询信息与…

【Java 进阶篇】使用 Java 和 Jsoup 进行 XML 处理

XML&#xff08;可扩展标记语言&#xff09;是一种常用的数据交换格式&#xff0c;它被广泛用于在不同系统之间传递和存储数据。Java作为一种强大的编程语言&#xff0c;提供了多种方式来处理XML数据。其中&#xff0c;Jsoup 是一个流行的Java库&#xff0c;用于解析和操作XML文…

vue3后台管理系统之跨域代理

vite.config.js中 server: {port: 5002,host: true, //0.0.0.0open: false,strictPort: true,proxy: {// 请求前缀/api&#xff0c;只有加了/api前缀的请求才会走代理(前端自定义)/api: {target: http://127.0.0.1:8000,// 获取服务器地址的设置changeOrigin: true,// 路径重写…

H5游戏源码分享-考眼力游戏猜猜金币在哪

H5游戏源码分享-考眼力游戏猜猜金币在哪 <!DOCTYPE html> <html> <head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8"><meta charset"UTF-8"><meta name"apple-mobile-web-app-capa…

国家网信办发布第十三批境内区块链信息服务备案编号

2019年2月15日《区块链信息服务管理规定》&#xff08;以下简称《管理规定》&#xff09;正式实施以来&#xff0c;国家互联网信息办公室依法依规组织开展备案审核工作&#xff0c;已发布2批次共506个境内区块链信息服务名称及备案编号&#xff0c;近日正式发布第三批共224个境…

若依ruoyi-nbcio如何做一个仿钉钉流程设计器的思考

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 看到有些流程图采用仿钉钉的流程设计&#xff0c;比如下面界面&#xff1a; 这种方式虽然简单&#xff0c…

shell中的运算

目录 1.运算符号 2.运算指令 练习 1.运算符号 运算符号意义加法-减法*乘法/除法%除法后的余数**乘方自加一- -自减一<小于<小于等于>大于>大于等于等于ji ->jji*j*i->jj*i/j/i->jj/i%j%i->jj%i 2.运算指令 (()) //((a12))let //let a12 …

Starknet开发工具

1. 引言 目前Starknet的开发工具流可为&#xff1a; 1&#xff09;Starkli&#xff1a;音为Stark-lie&#xff0c;为替换官方starknet-CLI的快速命令行接口。Starkli为单独的接口&#xff0c;可独自应用&#xff0c;而不是其它工具的组件。若只是想与Starknet交互&#xff0…

《算法通关村—最大小栈问题解析》

《算法通关村—最大小栈问题解析》 最小栈 描述 leetCode 155: 设计一个支持 push &#xff0c;pop &#xff0c;top 操作&#xff0c;并能在常数时间内检索到最小元素的栈。 实现最小栈 MinStack() 初始化堆栈对象。 void push(int val) 将元素val推入堆栈。 void pop()…

MVC架构_Qt自己的MV架构

文章目录 前言模型/视图编程1.先写模型2. 视图3. 委托 例子&#xff08;Qt代码&#xff09;例1 查询本机文件系统例2 标准模型项操作例3 自定义模型示例:军事武器模型例4 只读模型操作示例例5 选择模型操作例6 自 定 义委 托(在testSelectionModel上修改) 前言 在Qt中&#xf…

YouTube博主数据信息资源

YouTube博主数据信息资源 &#x1f525;我是一位拥有10年编程经验的程序猿&#xff0c;为你带来一个全新的优质资源 &#x1f50d;您是否在寻找最新、最活跃的YouTube博主数据&#xff0c;以助力你的项目、营销或研究&#xff1f; 我们的数据&#xff0c;您的优势&#xff1a;…

Azure - 机器学习实战:快速训练、部署模型

本文将指导你探索 Azure 机器学习服务的主要功能。在这里&#xff0c;你将学习如何创建、注册并发布模型。此教程旨在让你深入了解 Azure 机器学习的基础知识和常用操作。 关注TechLead&#xff0c;分享AI全维度知识。作者拥有10年互联网服务架构、AI产品研发经验、团队管理经验…