Spring框架之AOP详解

2023-11-19

理论

AOP 灵魂三问

1. AOP是什么?

AOP中文叫做面向切面编程,为Aspect Oriented Programming的首字符缩写。意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。通过名字可以看出,它与面向对象编程OOP名称相似。其实AOP就是OOP的进一步延伸。是Spring框架中的重要内容之一。

2. AOP有什么用?
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
简单来说:使用AOP可以在不修改源码的基础上,增加新的功能。(显而易见,这对于大型项目开发来说是极具诱惑的。减少了版本更迭时的工作量)

3. AOP是什么原理?
AOP代表的是一个横向的关系,相比于纵向的继承关系更加简便。将“对象”比作一个空心的圆柱体,其中封装的是对象的属性和行为;则面向方面编程的方法,就是将这个圆柱体以切面形式剖开,可以选择性的提供业务逻辑。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹,但完成了效果。

AOP的一些术语概念

  1. aspect (切面):切面由切点和通知组成,即包括横切逻辑的定义也包括连接点的定义

我的理解是 切面可以看作一个载体,在具体实现中的表现是一个切面类,类中包括切点和通知以及织入的动作等

  1. ponitcut (切点):每个类拥有多个连接点,可以看作连接点的集合

  2. joinpoint(连接点):程序执行的某个特定位置,如某个方法调用前后

我的理解:需要增强的目标类中的某个位置,及增强在这个位置调用

  1. weaving (织入):将增强添加到目标类的具体连接点的过程
  2. advice (通知) :是织入到目标类连接点上的一段代码,主要就是告诉需要增强到什么地方,需要增强的内容是什么。
  3. target (目标对象):通知织入的目标类
  4. aop Proxy (代理对象) :增强后产生的对象

Spring AOP 底层实现

通过JDK动态代理和CGLib代理在运行时期在对象初始化阶段织入代码的

  • JDK 动态代理:基于接口实现
  • CGLib 是基于类的继承实现的

五种通知形式

  • Before advice :前置通知,目标方法前执行,无论目标方法是否遇到异常都执行
  • After returning advice:后置通知,目标方法执行后执行,前提是目标方法没有遇到异常,遇到异常则不执行
  • After throwing advice:异常通知,顾名思义,在目标方法抛出异常时执行
  • After finally advice:最终通知,在目标方法执行后执行,无视是否异常
  • Around advice:环绕通知:最强大的通知类型,可以控制目标方法的执行(通过调用ProceedingJoinPoint.proceed() 执行目标方法),可以在目标执行全过程中执行。

实现

如何写切面类

  1. 定义一个切面类 Aspect

即声明的类, 增加@Component @Aspect 两个注解,Springboot中要引入spring-boot-stater-aop依赖包
@Component :告诉Spring 容器要扫描这个类
@Aspect:告诉Spring 这个类是个切面类

  1. 定义切点 Pointcut

定义切点,并定义切点在那些地方执行,采用@Pointcut注解
@Pointcut ( public * com.xxx.xxxx.*.(…) )
规则:括号内,修饰符(可以不写但不能用 *) + 返回类型 + 那些包下的类 + 那些方法 + 方法参数
” 表示不限,“…” 两个点表示参数不限

  1. 定义Advice 通知

利用通知的五种注解:@Before,@After,@AfterReturning,@AfterThrowing,@Around 来实现某些切点的增强动作,如@Before(“myPointcut()”),myPointcut为定义的切点

具体举例

这里创建的Springboot 项目,创建切面类,并在切面类中定义切点以及通知,利用输出日志信息来显示五种通知的不同执行时机。

首先
在Springboot项目中创建一个controller包,并再其下创建一个hellocontroller.java
在这里插入图片描述

在这个类的具体代码如下

package com.example.aopdeom.controller;

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

import java.io.IOException;

@RestController
public class hellocontroller {

    @GetMapping("/hello")
    public String hello(@RequestParam("name") String name) {
        return "Hello" + name;
    }

    @GetMapping("/bye")
    public String bye(@RequestParam("name") String name,@RequestParam("age") int age) throws IOException {
        if(age < 0){
            throw  new IOException();
        }
        return "Bye" + name + " age = " + age;
    }
}

其次
定义切面类myAdvice

其代码如下,定义了两个切点,并使用五种通知实现了五个通知,切点
myPointcut拦截的是controller包下的所有类的方法,而myPointcut2只针对controller包下bye方法,并且不限参数,及如果有同名而不同参的bye也会拦截。

package com.example.aopdeom;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;



@Aspect
@Component
public class myAdvice {
    private Logger logger = LoggerFactory.getLogger(myAdvice.class);

    //定义切面
    @Pointcut(value = "execution( * com.example.aopdeom.controller.*.*(..))")
    public void myPointcut(){

    }
    @Pointcut(value = "execution( * com.example.aopdeom.controller.hellocontroller.bye(..))")
    public  void myPointcut2(){

    }
    @Around("myPointcut()")
    public Object myLogger(ProceedingJoinPoint pjp) throws Throwable {
        String className = pjp.getTarget().getClass().toString();
        String methodName = pjp.getSignature().getName();
        Object[] array = pjp.getArgs();
        ObjectMapper mapper = new ObjectMapper();

        logger.info("调用前" + className + ":" + methodName + " 传递的参数:" + mapper.writeValueAsString(array));
        Object obj = pjp.proceed();
        logger.info("调用后:" + className + ":" + methodName + " 返回值:" + mapper.writeValueAsString(obj));
        return obj;
    }
    @Before("myPointcut2()")
    public void myLogger2(JoinPoint pjp) throws Throwable {
        String className = pjp.getTarget().getClass().toString();
        String methodName = pjp.getSignature().getName();
        Object[] array = pjp.getArgs();
        ObjectMapper mapper = new ObjectMapper();
        logger.info("前置通知:" + className + ":" + methodName + " 传递的参数:" + mapper.writeValueAsString(array));
    }
    @After("myPointcut2()")
    public void myLogger3(JoinPoint pjp) throws Throwable {
        String className = pjp.getTarget().getClass().toString();
        String methodName = pjp.getSignature().getName();
        Object[] array = pjp.getArgs();
        ObjectMapper mapper = new ObjectMapper();

        logger.info("最终通知" + className + ":" + methodName + " 传递的参数:" + mapper.writeValueAsString(array));
    }
    @AfterReturning("myPointcut2()")
    public void myLogger4(JoinPoint pjp) throws Throwable {
        String className = pjp.getTarget().getClass().toString();
        String methodName = pjp.getSignature().getName();
        Object[] array = pjp.getArgs();
        ObjectMapper mapper = new ObjectMapper();
        logger.info("返回后通知" + className + ":" + methodName + " 传递的参数:" + mapper.writeValueAsString(array));
    }
    @AfterThrowing("myPointcut2()")
    public void myLogger5(JoinPoint pjp) throws Throwable {
        String className = pjp.getTarget().getClass().toString();
        String methodName = pjp.getSignature().getName();
        Object[] array = pjp.getArgs();
        ObjectMapper mapper = new ObjectMapper();
        logger.info("异常通知" + className + ":" + methodName + " 传递的参数:" + mapper.writeValueAsString(array));
    }
}

测试

对于hello和bye调用时的情况。
输入的参数:
hello
在这里插入图片描述
bye
在这里插入图片描述
输出的日志:
hello
在这里插入图片描述
bye
在这里插入图片描述

当产生异常时,各个通知的情况
参数:
在这里插入图片描述
日志:
在这里插入图片描述
可以看到,产生日常后环绕通知中再方法执行后的日志不再输出,而且返回后通知也不再执行。

以上就是关于AOP的详细知识,以及demo的实现,感谢你的阅读,希望对你有所帮助,有什么建议可以在评论区留言

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring框架之AOP详解 的相关文章

随机推荐

  • 多个if语句并列_使用if-then 语句

    最基本的结构化命令就是if then语句 if then语句有如下格式 if command then commands fi 简单的例子 cat test1 sh bin bash testing the if statementif p
  • 开发工具链-DevOps_阿里云云效

    简介 阿里云效官网 DevOps Development和Operations的组合词 是一组过程 方法与系统的统称 用于促进开发 应用程序 软件工程 技术运营和质量保障 QA 部门之间的沟通 协作与整合 百度百科 快速开始 1 云效首页
  • 给导航网站新增了一些免费影视网站,欢迎体验

    使用时建议使用火狐浏览器 并安装广告屏蔽插件 这样就没有广告 视频内的广告千万不要相信 其余安心食用 地理导航 地理上网从这里开始
  • VS Code Remote Development

    配置VSCode Remote Development 1 Ubuntu 上启用 SSH 1 打开终端 并且安装openssh server软件包 sudo apt update sudo apt install openssh serve
  • 图像处理岗位面试题搜罗汇总

    传统图像处理部分 图像处理基础知识 彩色图像 灰度图像 二值图像和索引图像区别 彩色图像 RGB图像 灰度图像 0 255像素值 二值图像 0和1 用于掩膜图像 索引图像 在灰度图像中 自定义调色板 自定义输出256种颜色值 常用的图像空间
  • java 泛型 作用与定义

    1 泛型方法的定义和使用 public static void main String args throws ClassNotFoundException String str get 哈士奇 world System out print
  • Mac显示放大镜

    设置快捷键 系统默认是不开启热键的 如果需要设置 操作如下 设置 system preferences gt accessibility 在左侧找到room 进入配置窗口 按如上配置后 按住option键 然后两指向上就可以放大 两指向下就
  • 这座城市引领大模型浪潮!80余个AI大模型,一半集结在这里!

    刚刚结束的2023全球数字经济大会上 人工智能高峰论坛掀起了一股热潮 大型模型的发展和应用成为了会议的亮点 而作为这次盛会的主办方之一 北京市已经成为了这场人工智能革命的领先力量 作为人工智能产业的引领者 北京不负众望 国内已有80余个大型
  • Redis系列(七)Redis主从、哨兵、cluster集群方案解析

    文章目录 Redis主从 主从数据同步 同步 建立连接 完整重同步 全量同步 触发条件 部分重同步 增量同步 复制偏移量 offset 复制积压缓冲区 replication backlog buffer 部分重同步执行过程 命令传播 指令
  • 机器视觉最火应用领域

    1 图像和视频识别 人工神经网络领域最重要的进展之一出自 ImageNet ImageNet收集了 1400 万标签图像并于2009年发布 ImageNet挑战赛要求参赛者设计一个能够跟人类一样对照片进行分类的算法 但一直没有出现获胜者 直
  • Python图像处理 PIL中convert(mode)函数详解

    模式分类 PIL有九种不同模式 1 L P RGB RGBA CMYK YCbCr I F mode 1 代码示例 为二值图像 非黑即白 每个像素用8个bit表示 0表示黑 255表示白 from PIL import Image 读取一张
  • python快乐数字怎么表达_Python中的快乐数字

    在这里 我们将看到如何检测数字n是否为一个快乐数字 因此 快乐数字是一个数字 其中以任何正整数开头的数字均用其数字的平方和代替 该过程将重复进行直到其变为1 否则它将无休止地循环循环 这些数字 当找到1时 将成为快乐数字 假设数字为19 则
  • 类加载机制+双亲委派机制(通俗易懂版)

    1 类加载机制 一个类从加载到使用到卸载一共经过了5个步骤 加载 gt 连接 gt 初始化 其中连接分为验证 准备 解析三个阶段 1 加载 那么什么时候会将 class文件加载到jvm中 就是在你使用这个类的时候 验证 准备 解析 2 验证
  • 【计算机视觉】CLIP:语言-图像表示之间的桥梁

    文章目录 一 前言 二 架构 三 应用 3 1 图像分类 3 2 图像描述 3 3 文本到图像 四 总结 一 前言 最近GPT4的火爆覆盖了一个新闻 midjourney v5发布 DALLE2 midjourney都可以从文本中生成图像
  • 生成随机数

    目录 1 生成随机数sand 函数 2 srand 函数设置生成随机数 3 时间戳 4 如何生成规定位数的随机数呢 1 100 5 猜数字对生成随机数的应用 1 生成随机数sand 函数 这个函数会返回一个从0到RAND MAX的随机整数
  • 线性回归误差项方差的估计

    线性回归误差项方差的估计 摘要 线性回归误差项概念的回顾 残差平方和 residual sum of squares 残差平方和的期望 实验验证 参考文献 摘要 之前在文章线性回归系数的几个性质 中 我们证明了线性回归系数项的几个性质 在这
  • 微信小程序中组件间通信的三种方式

    事先准备 创建一个项目够 修改目录下的app json 在pages中注册页面 同时新增test1组件 也在app json中注册为全局组件 并命名为my test app json 配置 pages pages home home pag
  • JUnit4 initializationError[Runner:JUnit4](0.001s)junit4报错

    junit版本 4 12 如图 原因 缺少 依赖的jar hamcrest core 1 1 jar 添加后
  • vue判断undefined_这几个小技巧,让你书写不一样的Vue!

    前言 最近一直在阅读Vue的源码 发现了几个实战中用得上的小技巧 下面跟大家分享一下 同时也可以阅读我之前写的Vue文章 vue开发中的 骚操作 挖掘隐藏在源码中的Vue技巧 抽丝剥茧般的阅读源码 将 nextTick 拉下神坛 隐藏在源码
  • Spring框架之AOP详解

    Spring AOP 理论 AOP 灵魂三问 AOP的一些术语概念 Spring AOP 底层实现 五种通知形式 实现 如何写切面类 具体举例 理论 AOP 灵魂三问 1 AOP是什么 AOP中文叫做面向切面编程 为Aspect Orien