2023.12.2 关于 Spring AOP 详解

目录

Spring AOP

Spring AOP  常见使用场景

 AOP 组成

切面(类)

切点(方法)

通知

​编辑

前置通知(@Before)

后置通知(@After)

返回通知(@AfterReturning)

异常通知(@AfterThrowing)

环绕通知(@Around)

连接点

Spring AOP 实现  

 切点表达式说明

 Spring AOP 实现原理

织入

动态代理

JDK 动态代理

CGLIB


Spring AOP

  • AOP (Aspect Oriented Programming)译为 面向切面编程
  • AOP 为一种思想,是对某一类事情的集中处理
  • Spring AOP 是一个框架,提供了对 AOP 思想的实现
  • Spring AOP 是 Spring 的三大核心思想之一,另外两个是 IOC(控制反转)和 DI(依赖注入)

实例理解

  • 在我们程序中,经常存在一些系统性的需求
  • 这些需求代码会散落穿插在各个业务逻辑中,非常冗余且不利于维护,具有极高的耦合性
  • AOP 的目的就是将这些非业务代码完全提取出来,与业务代码分离,并寻找节点切入业务代码中

Spring AOP  常见使用场景

  • 统一登录检测机制
  • 统一方法的执行时间统计
  • 统一的返回格式设置
  • 统一异常处理
  • 事务的开始和提交

实例理解

  • 假设我们有一个 Web 应用其中有很多需要用户登录后才能访问的页面
  • 为了避免在每个需要登录的方法中都检查用户是否已经登录
  • 我们便可以使用 Spring AOP 来解决该问题

 AOP 组成

切面(类)

  • 在程序中就是对某一功能进行统一处理的类
  • 这个类包含了很多方法,这些方法就是由 切点 和 通知 组成

切点(方法)

  • 定义一个进行主动拦截的规则
  • 所谓的拦截就是 对用户向服务器发送的请求进行拦截,检测用户的操作是否符合预期,发现问题并统一处理的过程

通知

  • 通知就是 AOP 的具体执行动作
  • 在程序中被拦截后会触发一个具体的动作,即通知中具体实现的业务代码

  • 在 Spring 中可以在方法上使用以下注解,设置方法为通知方法,在满足条件后会通知本方法进行调用

前置通知(@Before)

  • 执行目标方法(实际要执行的方法)之前执行的方法

后置通知(@After)

  • 执行了目标方法之后执行的方法

返回通知(@AfterReturning)

  • 目标方法返回(return)的时候,执行的方法

异常通知(@AfterThrowing)

  • 在执行目标方法抛出异常时,执行的方法
  • 通常结合事务一起使用,如果未抛出异常则提交成功,如果抛出异常则回滚事务

环绕通知(@Around)

  • 在目标方法调用前、后都执行的通知
  • 如果已经有了前置和后置通知,再使用环绕通知,那么周期范围就在前置通知之前,后置通知之后
  • 通常可用于计算目标方法执行的时间


连接点

  • 所有可能触发切点的点就叫做连接点

Spring AOP 实现  

  • 此处我们想实现拦截 UserController 类中的所有方法

添加 Spring Boot AOP 依赖

  • 创建 Spring Boot 项目时,无法选择添加 Spring boot AOP 依赖
  • 所以我们可以选择进入 中央仓库 来选择与当前 Spring Boot 版本相对应的 AOP

<dependency>
    <groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

定义切面(类)

  • 使用 @Aspect 注解修饰该类,告诉 Spring Boot 该类为一个切面类
package com.example.demo.component;

import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect // 切面
@Component // 不能省略
public class UserAspect {
}

定义切点(方法)

  • 定义拦截规则,实现拦截 UserController 类中的所有方法
  • 使用 @Pointcut 修饰一个方法,该方法无需有方法体
  • 方法名就是起到一个标识的作用,标识通知方法具体指的是哪一个切点,因为切点可能有很多个
package com.example.demo.component;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect // 切面
@Component // 不能省略
public class UserAspect {
    
//    切点(配置拦截规则)
    @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
    public void pointcut() {
    }
}

创建通知

  • 此处我们创建三个通知
  • 前置通知、后置通知、环绕通知
package com.example.demo.component;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

@Aspect // 切面
@Component // 不能省略
public class UserAspect {

    //    切点(配置拦截规则)
    @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
    public void pointcut() {
    }

    /*
     * 前置通知
     * */
    @Before("pointcut()")
    public void beforeAdvice() {
        System.out.println("执行了前置方法");
    }

    /*
    * 后置通知
    * */
    @After("pointcut()")
    public void afterAdvice() {
        System.out.println("执行了后置方法");
    }

     /*
    * 环绕通知
    * 此处的 joinPoint 就是连接点,即方法本身
    * */
    @Around("pointcut()")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        Object obj = null;
        System.out.println("进入了环绕通知");
        obj = joinPoint.proceed();
        System.out.println("退出了环绕通知");
//        最后将执行的结果交给框架
        return obj;
    }
}

创建连接点

  • 此处我们对照 切点的拦截规则
  • 创建一个 UserController 类
  • 并在该类中创建两个连接点
  • 当我们在浏览器中访问这两个连接点时,会触发切点的拦截规则,对其进行拦截,然后执行各种通知
package com.example.demo.controller;

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

@RestController
public class UserController {

    @RequestMapping("/user/sayhi")
    public String sayHi() {
        System.out.println("执行了 sayHi 方法");
        return "hi spring boot aop";
    }

    @RequestMapping("/user/login")
    public String login() {
        System.out.println("执行了 login 方法");
        return "do user login";
    }
}

执行结果

  • 运行 Spring Boot 项目
  • 此处我们在浏览器中输入对应的 URL 地址,访问 UserController 中的 sayHi 方法


图示理解

 切点表达式说明

  • 该切点表达式属于 AspectJ 的语法
  • execution( <修饰符> <返回类型> <包.类.方法(参数)> <异常> )


实例理解

 Spring AOP 实现原理

  • Spring 的切面是代理类实现的
  • 代理类包裹了 目标对象
  • 即 用户只能先通过代理类,进行校验,如果没有问题才会进一步访问到目标对象

织入

  • 指代理生成的时机
  • 一般情况下,Spring AOP 动态代理的植入时机是程序的运行期

动态代理

  • Spring AOP 是构建在动态代理基础上的,所以 Spring 对 AOP 的支持局限于方法级别的拦截
  • Spring AOP 支持 JDK Proxy 和 CGLIB 方式实现动态代理

JDK 动态代理

  • 基于接口实现
  • 底层通过反射实现
  • 要求代理类一定要实现接口

CGLIB

  • 基于类的子类实现
  • 底层通过字节码增强技术生成子类实现
  • 不能代理被 final 修饰的类,因为其无法生成子类

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

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

相关文章

【接口测试】Apifox实用技巧干货分享

前言 不知道有多少人和我有着这样相似的经历&#xff1a;从写程序只要不报错就不测试&#x1f60a;&#xff0c;到写了程序若是有bug就debug甚至写单元测试&#xff0c;然后到了真实开发场景&#xff0c;大哥和你说&#xff0c;你负责的功能模块的所有接口写完要测试一遍无误在…

C# 使用HtmlAgilityPack解析提取HTML内容

写在前面 HtmlAgilityPack是一个HTML解析类库&#xff0c;日常用法就是爬虫获取到内容后&#xff0c;先用XPath获取目标节点&#xff0c;再用正则进行匹配&#xff1b;使用XPath的目的主要是将目标节点或内容限定在一个较小的范围&#xff0c;如果一上来就用正则那效率肯定不…

python——进程常用功能

Python的multiprocessing模块提供了强大的并行处理能力&#xff0c;以下是几个功能的详细解释&#xff1a; join(): 在multiprocessing中&#xff0c;join方法用于阻塞主进程直到指定的进程终止。这对于确保所有子进程在程序结束前完成其工作是很有用的。deamon(): 在multipro…

讲一讲redis的使用

Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的内存数据库系统&#xff0c;它提供了高性能、支持多种数据结构的存储和操作&#xff0c;被广泛应用于缓存、消息队列、计数器、实时分析等场景。以下是Redis的使用详解&#xff0c;涵盖了基本概念、数据结构…

目标检测常用评价指标

1 基本概念 1.1 IOU(Intersection over Union) 1.2 TP TN FP FN 2. 各种率 3. PR曲线 4. mAP的计算 4.1 AP的计算 4.2 mAP 4.3 mAP0.5和mAP0.5:0.95 1.1 IOU(Intersection over Union) 1.2 TP TN FP FN TP(Truth Positive)&#xff1a; 预测正类&#xff0c;实际正类&#x…

2022CVPR(PoseC3D):Revisiting Skeleton-based Action Recognition

Revisiting Skeleton-based Action Recognition 摘要1、引言2、相关工作3、框架3.1. 姿势提取的良好实践3.2.从2D姿势到3D热图体积3.3.基于骨架的动作识别的3D-CNN 4、实验4.2.姿势提取4.3. 3D热图体积的预处理4.4.与GCN的比较4.5. RGBPose-SlowFast4.6.与最先进的比较 5、结论…

糟了,数据库崩了,又好像没崩

前言 2023 年某一天周末&#xff0c;新手程序员小明因为领导安排的一个活来到公司加班&#xff0c;小明三下五除二&#xff0c;按照领导要求写了一个跑批的数据落库任务在测试环境执行 &#xff0c;突然间公司停电了&#xff0c;小明大惊&#xff0c;“糟了&#xff0c;MySQL …

wordpress建站优化加速教程-Redis加速

这篇文章适合宝塔面板&#xff0c;在宝塔面板安装 Redis 实现网站加速&#xff08; Redis是一个高性能的key-value数据库(PHP连接redis&#xff0c;需PHP设置中安装redis扩展) &#xff09;。对在word press网站有着明显的加速效果。关于Redis具体说明请自己百度&#xff0c;…

30岁左右的简历模板精选7篇

30岁左右是职业发展的关键时期&#xff0c;一份出色的简历能带来更多机会。本文精选了7篇适合30岁左右求职者的专业简历案例&#xff0c;无论您是寻找晋升、转行还是新的职业挑战&#xff0c;都能从中借鉴灵感&#xff0c;打造一份令人印象深刻的简历。 30岁左右的简历模板下载…

Git 配置文件(.gitignore)

前言 在使用 Git 分布式版本控制系统的时候&#xff0c;有些文件如&#xff1a;数据库的一些配置文件&#xff0c;我们不想让这类文件在远程仓库让 Git 来管理&#xff0c;不想让别人看到&#xff0c;此时就可以自己在 Git 仓库目录下创建 / 在远程仓库创建的时候就配置好 .git…

队列顺序存储(详解)

队列是一种常见的数据结构&#xff0c;它是一种先进先出&#xff08;First-In-First-Out, FIFO&#xff09;的线性表。在队列中&#xff0c;数据元素按照插入的顺序排列&#xff0c;最先插入的元素在队列的前面&#xff0c;最后插入的元素在队列的后面。类比生活中排队购物的情…

调试GMS应用,报错“此设备未获得play保护机制认证”问题解决

不少同学在调试GMS相关应用时&#xff0c;需登录Google账号&#xff0c;有时会弹出如下通知。 Google登录界面也会出现如下提示 这个报错的原因是设备未通过Google认证&#xff0c;google服务器未配置荣耀设备的型号白名单导致 国内网页有一些指导方法在鸿蒙\荣耀的设备上消除这…

语言模型文本处理基石:Tokenizer简明概述

编者按&#xff1a;近年来&#xff0c;人工智能技术飞速发展&#xff0c;尤其是大型语言模型的问世&#xff0c;让 AI 写作、聊天等能力有了质的飞跃。如何更好地理解和利用这些生成式 AI&#xff0c;成为许多开发者和用户关心的问题。 今天&#xff0c;我们推出的这篇文章有助…

Linux环境下 make/makefile、文件时间属性 详解!!!

1.项目自动化构建工具make/makefile 1.为什么要有make/makefile 我们先写一个简单的代码&#xff0c;然后编译生成一个可执行程序&#xff0c;下面的内容我们需要知道gcc识和编译链接的一些知识&#xff0c;不清楚的朋友们可以点这里http://t.csdnimg.cn/0QvL8 我们知道要想生…

Python爬虫:通过js逆向分析某翻译网站的原理

Python爬虫&#xff1a;通过js逆向分析某翻译网站的原理 1. 网站实现原理2. 抓取接口3. 参考代码和运行结果 1. 网站实现原理 首先&#xff0c;说一下爬取的网站&#xff1a;百度翻译。网站实现翻译的效果是通过接口实现的&#xff0c;也就是各位听到的ajax技术(只需要更换对应…

Spring | Spring的基本应用

目录: 1.什么是Spring&#xff1f;2.Spring框架的优点3.Spring的体系结构 (重点★★★) :3.1 Core Container (核心容器) ★★★Beans模块 (★★★) : BeanFactoryCore核心模块 (★★★) : IOCContext上下文模块 (★★★) : ApplicationContextContext-support模块 (★★★)SpE…

Mongoose 开源库--http协议 header 报头解析

一、http 协议 header 报头相关 API 获取http header的值 struct mg_str *mg_http_get_header(struct mg_http_message *hm, const char *name);参数&#xff1a; hm - HTTP message to look for header name - Header name返回值&#xff1a; HTTP header value or NULL i…

Docker下安装MySQL

如果在Docker下直接拉取MySQL并运行镜像&#xff0c;由于没有指定字符编码集&#xff0c;可能会存在插入中文出现乱码的情况&#xff0c;并且当容器删除后&#xff0c;容器里面存在的数据会丢失&#xff0c;所以在运行容器时应该使用数据卷进行挂载&#xff0c;按照如下步骤操作…

智慧城市包括哪些内容?有哪些智慧城市物联网方案?

数字城市、智慧城市的发展&#xff0c;离不开对公共基础设施的数字化、智慧化改造升级。通过融合边缘计算、5G、物联网、数字孪生、人工智能等新一代信息技术&#xff0c;助力传统公共基础设施提升增强全流程数据能力、计算能力、服务能力&#xff0c;从而不断丰富公共基础设施…

Kotlin:内置函数let、also、with、run、apply

前言 在Kotlin中&#xff0c;有一些用于扩展 & 方便开发者编码的内置函数&#xff0c;能大大提高开发者的开发效率。今天&#xff0c;我将主要讲解的是&#xff1a; let函数also函数with函数run函数apply函数 基础知识&#xff1a;接口回调中Lambda使用 在Kotlin中可使用…