SpringAOP的相关概念

news2024/11/16 15:26:46

文章目录

  • 一.什么是AOP
  • 二.AOP的组成部分
  • 三.SpringAOP的实现
    • 3.1 增加SpringAOP依赖
    • 3.2 创建切面
    • 3.2 创建切点
    • 3.3 创建通知
    • 3.4 创建连接点
  • 四.SpringAOP的实现原理
    • 4.1 JDK动态代理
    • 4.2 CGLIB 动态代理
    • 总结

一.什么是AOP

AOP,全称为Aspect-Oriented Programming(面向切面编程),是一种编程范式和软件设计思想。它是面向对象编程(OOP)的一种补充和扩展,用于解决OOP中的一些横切关注点(cross-cutting concerns)问题。
用一句话来概括的话,AOP (Aspect Oriented Programming)︰面向切面编程,它是一种思想,它是对某一类事情的集中处理。

二.AOP的组成部分

  • 切面
    我一般称之为类.这个切面值得就是具体的内容,一般来说,我们针对一个具体的内容,我们就称之为切面.举个例子来说,用户登录模块就是一个切面.

  • 切点
    切点,具体就是一个方法,它定义了拦截规则.

  • 通知
    如果说切点是方法的话,通知就是具体的一个实现代码.
    它里面有:
    1.前置通知:在目标方法(实际要执行的方法)调用之前执行的通知;
    2.后置通知:在目标方法调用之后执行的通知;
    3.环绕通知:在目标方法调用前、后都执行的通知l;
    4.异常通知:在目标方法抛出异常的时候执行的通知;
    5.返回通知:在目标方法返回的时候执行通知。

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

  • 织入
    将切面应用到目标对象中的过程,可以在编译时、加载时或运行时进行

三.SpringAOP的实现

3.1 增加SpringAOP依赖

这里不是spring自带的aop依赖,我们要去下载springboot的aop依赖

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    <version>2.7.14</version>
</dependency>

3.2 创建切面

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
@Aspect //切面
@Component //不能省略
public class UserAOP {
}

3.2 创建切点

//定义切点
    @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
    public void pointcut() {
    }

3.3 创建通知

 //前置通知
    @Before("pointcut()")
    public void doBefore() {
        System.out.println("执行了前置通知:" + LocalDateTime.now());
    }
    // 后置通知
    @After("pointcut()")
    public void doAfter() {
        System.out.println("执行了后置通知:" + LocalDateTime.now());
    }
    // 环绕通知
    @Around("pointcut()")
    //把方法本身给它
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("开始执行环绕通知了");
        Object obj = joinPoint.proceed();
        System.out.println("结束环绕通知了");
        return obj;
    }

3.4 创建连接点

@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 "hi spring boot aop.";
    }

}

在这里插入图片描述

在这里插入图片描述

四.SpringAOP的实现原理

Spring AOP是构建在动态代理基础上,因此Spring对AOP的支持局限于方法级别的拦截。
Spring AOP支持 JDK Proxy和CGLIB方式实现动态代理。默认情况下,实现了接口的类,使用AOP会基于JDK生成代理类,没有实现接口的类,会基于CGLIB生成代理类。

动态代理的常用实现方法有以下两种:
此种实现在设计模式上称为动态代理模式,在实现的技术⼿段上,都是在 class 代码运⾏期,动
态的织⼊字节码。

4.1 JDK动态代理

具体来说,当使用 JDK 动态代理时,需要定义一个实现 InvocationHandler 接口的类,并在该类中实现代理类的具体逻辑。然后,通过 Proxy.newProxyInstance() 方法来创建代理类的实例。该方法接受三个参数:类加载器、代理类要实现的接口列表和 InvocationHandler 对象
代码如下:

import org.example.demo.service.AliPayService;
import org.example.demo.service.PayService;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//动态代理:使用JDK提供的api(InvocationHandler、Proxy实现),此种方式实现,要求被代理类必须实现接口
public class PayServiceJDKInvocationHandler implements InvocationHandler {
    
    //目标对象即就是被代理对象
    private Object target;
    
    public PayServiceJDKInvocationHandler( Object target) {
        this.target = target;
    }
    
    //proxy代理对象
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //1.安全检查
        System.out.println("安全检查");
        //2.记录日志
        System.out.println("记录日志");
        //3.时间统计开始
        System.out.println("记录开始时间");

        //通过反射调用被代理类的方法
        Object retVal = method.invoke(target, args);

        //4.时间统计结束
        System.out.println("记录结束时间");
        return retVal;
    }

    public static void main(String[] args) {

        PayService target=  new AliPayService();
        //方法调用处理器
        InvocationHandler handler = 
            new PayServiceJDKInvocationHandler(target);
        //创建一个代理类:通过被代理类、被代理实现的接口、方法调用处理器来创建
        PayService proxy = (PayService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                new Class[]{PayService.class},
                handler
        );
        proxy.pay();
    }
}

4.2 CGLIB 动态代理

CGLIB 动态代理是一种使用 CGLIB 库来实现动态代理的技术。在 CGLIB 动态代理中,代理类不需要实现接口,而是通过继承被代理类来实现代理。 具体来说,当使用 CGLIB 动态代理时,需要定义一个继承被代理类的子类,并在该子类中实现代理类的具体逻辑。然后,通过 Enhancer.create() 方法来创建代理类的实例。该方法接受一个类作为参数,表示要代理的类,如下代码所示:

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.example.demo.service.AliPayService;
import org.example.demo.service.PayService;

import java.lang.reflect.Method;

public class PayServiceCGLIBInterceptor implements MethodInterceptor {

    //被代理对象
    private Object target;
    
    public PayServiceCGLIBInterceptor(Object target){
        this.target = target;
    }
    
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        //1.安全检查
        System.out.println("安全检查");
        //2.记录日志
        System.out.println("记录日志");
        //3.时间统计开始
        System.out.println("记录开始时间");

        //通过cglib的代理方法调用
        Object retVal = methodProxy.invoke(target, args);

        //4.时间统计结束
        System.out.println("记录结束时间");
        return retVal;
    }
    
    public static void main(String[] args) {
        PayService target=  new AliPayService();
        PayService proxy= (PayService) Enhancer.create(target.getClass(),new PayServiceCGLIBInterceptor(target));
        proxy.pay();
    }
}

总结

综上所述,动态代理的实现方法主要有 JDK 动态代理和 CGLIB 动态代理。JDK 动态代理中,代理类必须实现一个或多个接口,而 CGLIB 动态代理中,代理类不需要实现接口,但代理类不能是 final 类型,因为它是通过定义一个被代理类的子类来实现动态代理的,因此开发者需要根据具体的需求选择合适的技术来实现动态代理。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

创建jupyterlab的快捷启动的一种方式

1、找Jupyter Notebook的快捷图标 首先&#xff0c;找到Jupyter Notebook的快捷图标&#xff0c;打开其文件位置。 2、复制Jupyter Notebook快捷方式 复制Jupyter Notebook的快捷方式 将复制Jupyter Notebook的快捷方式的这两处的Noetbook修改为lab。 如下图 3、找Jupy…

RocketMQ概论

目录 前言&#xff1a; 1.概述 2.下载安装、集群搭建 3.消息模型 4.如何保证吞吐量 4.1.消息存储 4.1.1顺序读写 4.1.2.异步刷盘 4.1.3.零拷贝 4.2.网络传输 前言&#xff1a; RocketMQ的代码示例在安装目录下有全套详细demo&#xff0c;所以本文不侧重于讲API这种死…

Git的常用命令以及使用场景

文章目录 1.前言2.工作区,暂存区,版本库简介3.Git的常用命令4.版本回退5.撤销修改6.删除文件7.总结 1.前言 在学习Git命令之前,需要先了解工作区,暂存区和版本库这三个概念 2.工作区,暂存区,版本库简介 在使用Git进行版本控制时&#xff0c;有三个重要的概念&#xff1a;工作…

day48-ajax+SSM分页

AjaxSSM分页 非分页版controller及html&#xff1a; 分页模糊查询controller&#xff1a; Postman测试&#xff08;无网页&#xff09;&#xff1a; 分页网页&#xff1a; 分页网页中添加模糊查询&#xff1a; 分页网页中实现添加功能&#xff1a; &#xff08;1&am…

VUE3-04

1. 编写代码过程中的问题与解决 1.1 错误&#xff1a;cant read property of undefined(name) &#xff08;1&#xff09;首先定位错误的位置 &#xff08;2&#xff09;逐一排查问题&#xff1a;注释代码&#xff1b;debugger&#xff1b;console.log &#xff08;3&#xff0…

10.Docker安全和https

文章目录 Docker安全Docker存在的安全问题Docker架构缺陷与安全机制Docker 安全基线标准Docker安全总结 HTTPSHTTPS访问过程生成证书方式openssL生成证书过程 Docker安全 容器的安全性问题的根源在于容器和宿主机共享内核。如果容器里的应用导致Linux内核崩溃&#xff0c;那么…

Spring Tool Suite 4

参考&#xff1a;Spring tool suite4 安装及配置_springtoolsuite4_猿界零零七的博客-CSDN博客 下载&#xff1a;Spring | Tools 将下载的JAR进行解压两次&#xff0c;直至解压出contents中的sts 双击启动 第一次打开需要指定工作区文件夹 配置Maven的config 安装插件

C++ new/delete的使用

1.虚拟地址空间 可执行程序&#xff08;进程&#xff09;的虚拟地址空间&#xff1a; 内核&#xff1a;操作系统 栈区&#xff1a;函数的形参&#xff0c;非静态的局部变量&#xff0c;函数现场保护数据等等&#xff0c;栈是向下增长的&#xff0c;栈顶是低地址&#xff0c;栈…

基于fpga_EP4CE6F17C8实现的呼吸灯

文章目录 前言实验手册&#xff08;EP4CE6F17C8&#xff09;一、实验目的二、实验原理理论原理 三、系统架构设计四、模块说明1&#xff0e;模块端口信号列表2&#xff0e;状态转移图3&#xff0e;时序图 五、仿真波形图六、引脚分配七、代码实现八、仿真代码九、板级验证效果 …

[CrackMe]damn.exe的逆向及注册机编写

1. 脱壳过程 这个crackme有2个文件 发现加了壳 先来脱壳, 使用ESP守恒, pushad后立马下硬件访问断点 F9直接运行, 立马到popad处 接着走几步就到了OEP 下面使用LordPE来转储映像, 为了防止别人修改PE中的ImageSize, 先尝试修正下ImageSize, 然后dump full即可 接着用x6…

《重构的时机和方法》——让你的代码更健壮、更易维护

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小黄&#xff0c;独角兽企业的Java开发工程师&#xff0c;CSDN博客专家&#xff0c;阿里云专家博主&#x1f4d5;系列专栏&#xff1a;Java设计模式、Spring源码系列、Netty源码系列、Kafka源码系列、JUC源码…

简述IO(BIO NIO IO多路复用)

在unix网络变成中的五种IO模型: Blocking IO(阻塞IO) NoneBlocking IO (非阻塞IO) IO mulitplexing(IO多路复用) signal driven IO (信号驱动IO) asynchronous IO (异步IO) BIO BIO&#xff08;Blocking IO&#xff09;是一种阻塞IO模型&#xff0c;也是传统的IO操作模型之一…

不管如何吐槽,购买iPhone的用户依然义无反顾,苹果继续增长

市调机构IDC公布的二季度数据显示&#xff0c;苹果成为前五名之中除华为之外第二家取得增长的手机品牌&#xff0c;而其他国产手机品牌的出货量都在下滑&#xff0c;显示出国内的消费者仍然在热烈追捧iPhone。 二季度苹果在国内市场的手机出货量同比增长6%&#xff0c;虽然增速…

查看详细的退货信息!亚马逊在卖家中心推出新页面!

亚马逊欧洲站发布公告称亚马逊在卖家中心推出了一个新页面&#xff0c;为卖家提供详细的退货信息&#xff0c;以下是公告内容&#xff1a; 我们在卖家中心推出了一个新页面&#xff0c;为卖家提供详细的退货信息。 现在卖家可以查看每个退货订单&#xff0c;其中包含有关 ASI…

sky-notes-01

1、DTO类 DTO&#xff08;Data Transfer Object&#xff09;&#xff1a;数据传输对象&#xff0c;Service 或 Manager 向外传输的对象。 详见阿里巴巴Java开发手册中的DO、DTO、BO、AO、VO、POJO定义 当前端提交的数据和实体类中对应的属性差别比较大时&#xff0c;建议使用…

【信号去噪和正交采样】流水线过程的一部分,用于对L波段次级雷达中接收的信号进行降噪(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

信号的学习笔记二

文章目录 信号捕捉signal信号捕捉sigaction信号集未决信号集和阻塞信号集的工作过程 ![在这里插入图片描述](https://img-blog.csdnimg.cn/b896346af6f1462089779e513a7e237b.png)信号集相关函数sigemptysetsigfillsetsigaddsetsigdelsetsigismember应用 以下函数设置内核信号集…

上传图片到腾讯云对象存储桶cos 【腾讯云对象存储桶】【cos】【el-upload】【vue3】【上传头像】【删除】

1、首先登录腾讯云官网控制台 进入对象存储页面 2、找到跨越访问CIRS设置 配置规则 点击添加规则 填写信息 3、书写代码 这里用VUE3书写 第一种用按钮出发事件形式 <template><div><input type="file" @change="handleFileChange" /&…

[NLP]LLM高效微调(PEFT)--LoRA

LoRA 背景 神经网络包含很多全连接层&#xff0c;其借助于矩阵乘法得以实现&#xff0c;然而&#xff0c;很多全连接层的权重矩阵都是满秩的。当针对特定任务进行微调后&#xff0c;模型中权重矩阵其实具有很低的本征秩&#xff08;intrinsic rank&#xff09;&#xff0c;因…

labelme标签格式json转化成yolov8支持是数据集格式

我们用yolov8做实例分割时&#xff0c;需要制作标签&#xff0c;如果用labelme做&#xff0c;不能直接用模型训练&#xff0c;需要利用一个脚本文件进行转换。 import base64 import random import shutil from tqdm import tqdm import math import json import os import nu…