Spring Aop的学习(一):Spring Aop的简单入门

news/2024/4/28 16:19:23/文章来源:https://www.cnblogs.com/mcj123/p/16819370.html

1. 什么是AOP

AOP(Aspect Oriented Programming):面向切面编程,是OOP(面向对象编程)的一个延续,其和OOP一样,也是一种编程思想。不过AOP是一种横向开发模式。

2. AOP的作用及应用场景

  • 作用
    AOP的主要作用就是减少代码量,提高代码的可重用性,有利于未来的可操作性与可维护性。
    主要操作就是将所有模块中共同拥有的代码,单独抽取出来,放在一块地方,在主代码运行之前或之后,或主程序运行的其他时间点执行这块代码。也可以理解成把这些单独抽出来的代码封装成一个个单独的方法,但是这些方法的执行不需要我们在程序中进行显示的调用,而是通过动态代理(jdk动态代理和cglib动态代理)的方式来帮助我们执行这些方法。
  • 应用场景
    AOP的主要应用场景是一些相似性代码比较高的场景,比如:权限认证,日志,事务等。

3. AOP的术语

1.连接点(Joinepoint):是程序执行的某个特定位置,如类开始初始化前、类初始化后、类的某个方法调用前/后、方法抛出异常后。一个类或者一段程序代码拥有一些具有边界性质的特定点,这些特定点就称为 “连接点” 。这边有个注意的点就是spring的链接点只支持方法,也就是只能是方法在调用前,调用后,抛出异常后。
2.切点(Pointcut):切点就是能够定位到特定连接点的点。也就是能够通过切点知道程序在哪个连接点之前或之后执行。
3.增强(Advice):增强说白了就是你想要在切点上执行的代码逻辑,也就是在连接点之前或之后执行的那段代码。
4.目标对象(Target):就是你要插入代码的类,也就是连接点所在的类。
5.引介(Introduction):是一种特殊的增强,为类添加一些属性和方法。
6.织入(Weaving):是一个过程,就是将增强添加到目标类具体连接点上的过程。
7.代理(Proxy):就是融合了目标类和增强逻辑后生成的那个对象
8.切面(Aspect):由切点和增强组成,包含了切点的定义与增强的代码逻辑的定义

4. 如何使用AOP

使用AOP的方式主要有两种,一种是基于xml文件进行开发,另一种是基于注解进行开发,这边主要是讲的基于注解的进行开发的方式。

4.1. 引入依赖

        <!--AOP的依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>

4.2. 注解介绍

@Aspect:声明一个切面,标注在类,接口或枚举上。
image

@Pointcut:声明切入点,即切入到哪些目标类的目标方法,标注在方法上。
image
value的值是指定切入点表达式,常用的主要有两种表达式,一种是execution(),另一种是annotation():

  • execution()表达式
    语法:execution(方法修饰符(可选) 返回类型 方法名 参数 异常模式(可选))
    参数部分允许使用通配符:
    * 匹配任意字符,但只能匹配一个元素。
    .. 匹配任意字符,可以匹配任意多个元素,表示类时,必须和*联合使用。
    + 必须跟在类名后面,如Horseman+,表示类本身和继承或扩展指定类的所有类
  • annotation()表达式
    此方式是针对某个注解来定义切面,一般对于自定义注解常使用annotation()表达式,比如我们对具有 @PostMapping 注解的方法做切面,可以如下定义切面:
    @Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)")

@Before:前置通知,在切入点执行之前执行,也就是在执行切入点之前执行这个方法中的代码,但是如果这个方法中抛出了异常那么就不会再执行切入点的方法。和@Pointcut一样作用在方法上。
image
其中value的值可以是指定切入点表达式,也可以是由@Pointcut注解标注的方法,如果是指定切入点表达式的话这边是和@Pointcut注解一样的。
@After:后置通知,在执行切入点方法之后执行,也就是执行了切入点的方法之后,会再执行@After注解标注的方法。其同样是作用在方法上的注解:
image
其中value的值可以是指定切入点表达式,也可以是由@Pointcut注解标注的方法,如果是指定切入点表达式的话这边是和@Pointcut注解一样的。这个的value与@Before注解的value值一样。
@AfterReturning:返回通知,在切入点返回结果之后执行,这个结果是在@After注解之后执行的,其同样是作用在方法上:
image
其中value的属性与@Before和@After注解的value一样。pointcut属性则是绑定同通知的契入点表达式,需要注意的是它的优先级高于value,也就是pointcut与value都填写的话会优先以pointcut的为准。
@AfterThrowing:异常通知,这个则是在抛出异常之后进行执行,另外,需要注意的是如果目标方法自己try-catch了异常,而没有继续往外抛出,则不会进入此回调函数。其同样是作用在方法上:
image
他的属性值和@AfterReturning的属性值基本上一样。同样是pointcut的优先级高于value的
@Around:环绕通知,这个则是在切入点执行之前或执行之后都分别执行一些代码,还可以控制目标方法的执行。它是早于前置通知,晚于返回通知。其同样是作用在方法上的注解:
image
其中value的属性与@Before注解和@After注解的value属性一样。需要注意的是环绕通知标注的方法有一个必须的参数ProceedingJoinPoint,这个参数主要是用来执行目标方法,以及获取目标方法的一些信息。

4.3. 定义切点、切面以及通知

package com.mcj.music.aspect;import com.mcj.music.utils.AspectUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;
import java.util.Map;/*** @author mcj* @date 2022/10/23 9:54* @email 2037612492@qq.com* @description 日志的切面类,为controller类中的每个方法添加日志*/
@Aspect                // 定义切面
@Component
@Slf4j
public class LogAspect {/*** execution函数用于匹配方法执行的连接点,语法为:* execution(方法修饰符(可选)  返回类型  方法名  参数  异常模式(可选))* 参数部分允许使用通配符:* *  匹配任意字符,但只能匹配一个元素* .. 匹配任意字符,可以匹配任意多个元素,表示类时,必须和*联合使用* +  必须跟在类名后面,如Horseman+,表示类本身和继承或扩展指定类的所有类* 此处表示返回类型、参数不限,只要是com.mcj.music.controller包中的任何类中的任何方法*/@Pointcut("execution(* com.mcj.music.controller.*.*(..))")      // 定义切点public void logPointcut(){}/*** 环绕通知,在执行每个controller类中的方法之后打印相关的日志* @param joinPoint* @return* @throws Throwable*/@Around("logPointcut()")                                       // 进行环绕通知public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {String paramNameAndValue = AspectUtils.getParamNameAndValue(joinPoint);String methodName = AspectUtils.getMethod(joinPoint);Object proceed = joinPoint.proceed();log.info("当前请求方法:{},当前请求参数名与参数:{},当前请求结果:{}", methodName, paramNameAndValue, proceed);return proceed;}@Before("logPointcut()")public void doBefore() {System.out.println("这是前置通知");System.out.println("--------------------------------------------");}@After("logPointcut()")public void doAfter() {System.out.println("这是后置通知");System.out.println("--------------------------------------------");}@AfterReturning("logPointcut()")public void doAfterReturning() {System.out.println("这是返回通知");System.out.println("--------------------------------------------");}@AfterThrowing("logPointcut()")public void doAfterThrowing() {System.out.println("这是异常通知");System.out.println("--------------------------------------------");}}

AspectUtils工具类

package com.mcj.music.utils;import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.CodeSignature;import java.util.HashMap;
import java.util.Map;/*** @author mcj* @date 2022/10/23 10:15* @email 2037612492@qq.com* @description*/
@Slf4j
public class AspectUtils {/*** 获取当前切点的参数名称与值* @param joinPoint* @return*/public static String getParamNameAndValue(ProceedingJoinPoint joinPoint) {Map<String, Object> paramNameAndValueMap = new HashMap<>(8);Object[] args = joinPoint.getArgs();String[] parameterNames = ((CodeSignature) joinPoint.getSignature()).getParameterNames();for (int i = 0; i < parameterNames.length; i++) {paramNameAndValueMap.put(parameterNames[i], args[i]);}return JSONObject.toJSONString(paramNameAndValueMap);}/*** 获取当前切点的全限定方法名* @param joinPoint* @return*/public static String getMethod(ProceedingJoinPoint joinPoint) {// 获取当前切点的全限定类型String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();// 获取当前切点的方法名String name = joinPoint.getSignature().getName();return declaringTypeName + "." + name;}}

执行结果:
image
由于方法在执行的过程中出现异常,根本没有返回值,所以也不会有返回通知了。
image

5. 总结

spring AOP的简单入门使用并不是很难,基本上最主要的就是切面与切点的定义,至于它的几种通知类型,最主要的就是@Around环绕通知。至于AOP的实现原理动态代理,这个后面再找时间看吧。

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

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

相关文章

2022-2023-1 20221424《计算机基础与程序设计》第9周学习总结

2022-2023-1 20221424《计算机基础与程序设计》第9周学习总结 作业信息这个作业属于哪个课程 2022-2023-1-计算机基础与程序设计这个作业要求在哪里 2022-2023-1计算机基础与程序设计第一周作业这个作业的目标 操作系统责任,内存与进程管理,分时系统,CPU调度,文件、文件系统…

《JavaSE-第十五章》之文件(二)

前言 在你立足处深挖下去,就会有泉水涌出!别管蒙昧者们叫嚷:“下边永远是地狱!” 博客主页&#xff1a;KC老衲爱尼姑的博客主页 博主的github&#xff0c;平常所写代码皆在于此 刷题求职神器 共勉&#xff1a;talk is cheap, show me the code 作者是爪哇岛的新手&#xff0c;水…

neovim图标显示乱码,utf8字体显示乱码(Windows10和Centos安装nerd-fonts)

前言 作为一名想成为大神的菜鸟程序员&#xff0c;一个牛X的代码编辑环境是必不可少的&#xff0c;在这里我推荐neovim和emacs。我使用的是neovim&#xff0c;github上有neovim-from-scratch工程可以一步一步学习搭建&#xff0c;B站上也有相关视频可供学习&#xff0c;在这里…

升级python环境时gdal出现缺少proj的问题

gdal在做坐标转换时报出如此的错误。原系统的代码没有改变&#xff0c;为了更新sentinelhub包&#xff0c;将python环境由3.6升级至3.7。升级了python环境之后&#xff0c;所有相关的py包和第三方库重新进行安装。安装过程中基本没有遇到问题。但是在运行代码时gdal报出错误。 …

IDEA全局搜索快捷键方法

1、CtrlN 按名字搜索类 相当于eclipse的ctrlshiftR&#xff0c;输入类名可以定位到这个类文件&#xff0c;就像IDEA在其他的搜索部分表现一样&#xff0c;搜索类名也能对你所要搜索的内容多个部分进行匹配&#xff0c;而且如果能匹配的自己写的类&#xff0c;优先匹配自己写的类…

java实验报告4;

一、实验目的:【目的要求】 了解接口和抽象类的使用 熟悉类中成员的定义及权限的设定 掌握完整类的设计 【注意事项】 注意电源插座的用电安全&#xff1b; 遵守计算机的使用注意事项&#xff1b; 防范病毒。 二、使用工具 电脑 window系统 JDK环境 eclipse开发环境…

本博主二哈喇子!特此声明

免责声明 本博主二哈喇子&#xff01;为了避免各种纠纷&#xff0c;特做如下说明: 本博主一向尊重他人的知识产权&#xff0c;同时也注意保护自己的知识产权&#xff0c;因此建议您在进入本博客的各个页面前&#xff0c;请务必仔细阅读本声明。 一切网民以任何方式在进入本博客…

模拟登陆系统

1.问题 日常生活中我们会遇到许多需要密码来登陆账户的场景&#xff0c;如何使用Java来创建此类登陆代码呢&#xff1f; 2.方法 import java.util.Scanner; public static void main (String[] args) { Scanner sc new Scanner (System.in); int count 3; while(cou…

控制“恶意”代码,安全运行沙箱类技术崛起

据CNNIC的最新估算&#xff0c;截至10月31日&#xff0c;我国上网用户人数达到5800万&#xff0c;上网计算机数升至2300万&#xff0c;从七月份至今&#xff0c;在短短的四个月间分别增加了1220万和687万。 这预示着我国互联网在经过一段时间的发展低潮之后正在开始回暖。 但…

贪婪算法(Huffman编码)

如果一个算法分阶段的工作&#xff0c;并且在每一个阶段都认为所做的决定是最好的&#xff0c;而不考虑将来的后果&#xff0c;这样的算法就叫做贪婪算法。贪婪算法只考虑当前局部的最优解&#xff0c;而不去考虑全局的情况&#xff0c;如果最终得到的结果是全局最优的&#xf…

【pytest官方文档】解读- 开发可pip安装的第三方插件

在上一篇的 hooks 函数分享中,开发了一个本地插件示例,其实已经算是在编写插件了。今天继续跟着官方文档学习更多知识点。 一个插件包含一个或多个钩子函数,pytest 正是通过调用各种钩子组成的插件,实现了配置、搜集、运行和报告的所有方面的功能。 通常 pytes t中的插件有…

OS实战笔记(7)-- Linux同步机制

上一篇笔记中对x86平台上原子变量、关中断、自旋锁和信号量的原理做了复习&#xff0c;本笔记回顾一下Linux使用的几种常用的同步机制。 Linux上的原子变量 Linux上提供了一个atomic_t类型表示原子变量。32位和64位版本的结构体定义如下&#xff1a; typedef struct {int coun…

文件描述符0,1,2+lseek()+共享文件覆盖解决

1.文件描述符0&#xff0c;1&#xff0c;2 程序开始运行时&#xff0c;有三个文件被自动打开&#xff0c;打开时分别使用了这三个文件描述符依次打开的三个文件分别是 /dev/stdin&#xff0c;/dev/stdout&#xff0c;/dev/stderr /dev/stdin 标准输入文件 程序开始运行时&…

requests模块和openpyxl模块

第三方模块的下载和使用 1,第三方模块就是别人大神们已经写好的模块,功能特别强大。我们如果像使用第三方模块就先要进行下载。下载完成后 才可以在python中直接调用2.下载方式一:pip工具pip工具注意每个解释器都有pip工具 如果我们的电脑上有多个版本的解释器那么我们在使用…

模型交易平台--信用卡客户消费行为分析

业务问题&#xff1a; 据《中国银行卡产业发展蓝皮书&#xff08;2021&#xff09;》显示&#xff0c;截至2020年末&#xff0c;中国信用卡累计发卡量为11.3亿张&#xff0c;其中6个月内有使用记录的活卡为7.4亿张&#xff0c;有近4亿张信用卡处于“睡眠”状态。 睡眠信用卡…

【JUC】12.读写锁与StampedLock[完结]

文章目录1. 什么是读写锁2. 锁的演化历程3. 锁降级4. 锁降级的策略5. StampedLock简介6. StampedLock的特点7. StampedLock之传统读写8. StampedLock之乐观锁9. StampedLock缺点1. 什么是读写锁 读写锁是指ReentrantReadWriteLock类 该类能被多个读线程访问或者一个写线程访问…

第二节:数据类型与变量【java】

目录 &#x1f4c3;前言 &#x1f4d7;1.数据类型 &#x1f4d5;2. 变量 2.1 变量概念 2.2 语法格式 &#x1f4d9;3.整型变量 3.1 整型变量 3.2 长整型变量 3.3 短整型变量 3.4 字节型变量 &#x1f4d8;4.浮点型变量 4.1 双精度浮点型 4.2 单精度浮点型 &#…

拓端tecdat|用Python进行图像模糊处理和特征提取

全文链接&#xff1a;http://tecdat.cn/?p9015 原文出处&#xff1a;拓端数据部落公众号 在本文中&#xff0c;我将带您了解图像处理的一些基本功能。特征提取。但是这里我们需要更深入的数据清理。但是数据清理是在数据集&#xff0c;表格&#xff0c;文本等上完成的。如何在…

vue使用canvas实现手写电子签名;vue使用vue-esign插件实现手写电子签名;H5使用画布签名

功能&#xff1a; 1.兼容 PC 和 Mobile&#xff1b; 2.画布自适应屏幕大小变化&#xff08;窗口缩放、屏幕旋转时画布无需重置&#xff0c;自动校正坐标偏移&#xff09;&#xff1b; 3.自定义画布尺寸&#xff08;导出图尺寸&#xff09;&#xff0c;画笔粗细、颜色&#xff0…

Arduino UNO 可视化GT-24工业级无线透传

Arduino UNO 可视化GT-24工业级无线透传一、前言二、硬件要求三、参数基础四、原理剖析五、透传思路六、程序概要七、arduino使用接线八、成果展示一、前言 无线透传市面上较为常见的是基于蓝牙、esp的多种透传模块&#xff0c;今天介绍的则是用NRF24L01芯片构成的电路。&…