Spring AOP之MethodInterceptor原理

news2025/1/11 22:37:27

文章目录

    • 引言
    • Spring AOP组成
      • 先看一下Advice
    • 示例
      • 提问
    • 原理

引言

之前我们讨论过了HandlerInterceptor,现在我们来看一下MethodInterceptor。
MethodInterceptor是Spring AOP中的一个重要接口,用来拦截方法调用,它只有一个invoke方法。

Spring AOP组成

  1. Aspect:切面,是一个普通的Java类,里面定义了通知(Advice)和切点(Pointcut)。
  2. Advice:通知,定义了切面要织入目标对象的具体时机和操作。有前置通知、后置通知、异常通知、最终通知和环绕通知等。
  3. Pointcut:切点,指明应用通知的具体对象和方法。可以通过表达式或匹配命名规范来指定切点。
  4. Target:目标对象,被通知和切点织入额对象。
  5. Weaving:织入,将切面应用到目标对象来创建代理对象的过程。Spring AOP中通常在运行期间通过动态代理来实现。

先看一下Advice

Spring AOP支持5种类型的Advice(通知),执行时机和简单解释如下:

通知名执行时机解释
@Before目标方法执行前在目标方法执行前执行,可以用于方法级预处理
@AfterReturning目标方法执行后,且没有异常用于方法后置处理,获取方法返回值等
@After目标方法执行后,不论方法异常与否用于资源清理
@AfterThrowing目标方法抛出异常后处理方法中抛出的异常
@Around环绕目标方法在目标方法执行前后都可以执行自定义操作,并控制目标方法是否执行及其参数

这5种Advice的执行顺序如下:

  1. @Before:前置通知,目标方法执行之前执行
  2. @Around:环绕通知, encloses 目标方法,在目标方法之前和之后执行自定义操作
  3. 目标方法执行
  4. @AfterReturning:返回通知,目标方法成功执行之后执行
  5. @AfterThrowing:异常通知,目标方法抛出异常后执行
  6. @After:后置通知,目标方法之后执行
    所以总结来说:
    @Before,@After在目标方法执行前后一定会执行。
    @AfterReturning只有目标方法成功执行后才会执行。
    @AfterThrowing只有目标方法抛出异常后才会执行。
    @Around会根据是否执行目标方法而在前后执行,还可以控制目标方法的执行。

偷了一张图,可以参考一下:
来源:https://zhuanlan.zhihu.com/p/500555634
来源:Spring AOP通知(Advice)详解

示例

我们直接来个例子
pom文件,我用的gradle:

plugins {
    id 'org.springframework.boot' version '3.0.2'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'


repositories {
    mavenLocal()
    maven { url "https://maven.aliyun.com/nexus/content/groups/public/"}
    mavenCentral()
    jcenter()
    maven { url "https://repo.spring.io/snapshot" }
    maven { url "https://repo.spring.io/milestone" }
    maven { url 'https://oss.jfrog.org/artifactory/oss-snapshot-local/' }
}


dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    implementation 'org.springframework.boot:spring-boot-starter-aop'
}

service接口和类

public interface ExampleService {
    void doSomething();

    void doAnything();


    void justPlay();
}

@Service
public class ExampleServiceImpl implements ExampleService {
    @Override
    public void doSomething() {
        System.out.println("-----------doSomething ----------");
    }    
	
	@Override
    public void doAnything() {
        System.out.println("-----------doAnything ----------");

    }

    @Override
    public void justPlay() {
        System.out.println("-----------justPlay ----------");

    }
}

切面类:

@Aspect
@Component
public class ExampleAspect {

//只拦截do开头的方法
    @Before("execution(* com.example.gspringtest.service.impl.ExampleServiceImpl.do*(..))")
    public void beforeMethod() {
        System.out.println("Before method");
    }
}

测试接口:


package com.example.gspringtest.demos.web;

import com.example.gspringtest.service.ExampleService;
import com.example.gspringtest.service.impl.ExampleServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
 */
@Controller
public class BasicController {

    @Autowired
    private ExampleService exampleService;
    @Autowired
    private ApplicationContext applicationContext;

    @RequestMapping("/testMethod")
    @ResponseBody
    public String testMethod() {
        exampleService.doSomething();

        System.out.println("******************888888888********************");

        exampleService.doAnything();

        System.out.println("******************888888888********************");

        exampleService.justPlay();
//        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        ExampleService exampleService1 = applicationContext.getBean(ExampleServiceImpl.class);
        ExampleServiceImpl exampleService2 = applicationContext.getBean(ExampleServiceImpl.class);

        return "Hello " ;
    }
}

先来看一下输出

Before method
-----------doSomething ----------
******************888888888********************
Before method
-----------doAnything ----------
******************888888888********************
-----------justPlay ----------

提问

请告诉我,测试接口中的exampleService,exampleService1和exampleService2是同一个bean吗?是代理类还是原对象?

来揭晓一下答案:

首先是同一个bean
在这里插入图片描述
其次,只能拿到代理类:
在这里插入图片描述

原理

上面讲了这么多,好像跟MethodInterceptor没啥关系啊,我们
先来看几个类:

MethodBeforeAdviceAdapter
执行Before方法

AfterReturningAdviceInterceptor
执行AfterReturning方法

ThrowsAdviceInterceptor
执行AfterThrowing方法

AspectJAfterAdvice
执行Aftor方法

AspectJAroundAdvice
执行Around方法

这几个类都实现了MethodIntercepter,并且分别对应了不同的通知类型。

spring aop为目标对象生成的代理对象是通过实现MethodInterceptor接口来与拦截器协同工作的。

代理对象通过实现MethodInterceptor接口并协调拦截器链,与各MethodInterceptor实现相结合,最终执行完所有相关通知逻辑并将结果返回给客户端。
拦截器链中的每个拦截器通过mi.proceed()调用下一级,并在前/后执行本拦截器的通知逻辑,形成完整的通知调用链。

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

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

相关文章

Laya3.0游戏框架搭建流程(随时更新)

近两年AI绘图技术有了长足发展&#xff0c;准备把以前玩过的游戏类型重制下&#xff0c;也算是圆了一个情怀梦。 鉴于unity商用水印和启动时间的原因&#xff0c;我决定使用Laya来开发。目前laya已经更新到了3.0以上版本&#xff0c;就用目前比较新的版本。 之后关于开发中遇到…

HashMap学习:1.7 迁移死循环分析(通俗易懂)

前言 JDK1.7由于采用的头插法&#xff0c;所以多线程情况下可能会产生死循环问题。 正文 头插法 就是每次从旧容器中的hash桶中取出数据后&#xff0c;放到新容器的头节点问题&#xff0c;如果此时头结点位置为空&#xff0c;直接放置即可&#xff0c;如果不为空将头节点的数…

C语言strncpy的使用缺陷和实现,strncat的使用缺陷和实现,strncmp的使用和实现。

1.strncpy 函数原型&#xff1a; char *strncpy( char *strDest, const char *strSource, size_t count );char *strDest 目标字符串首元素地址const char *strSource 源字符串(需要拷贝过去的字符串)size_t count 拷贝字符的个数char *strncpy 拷贝结束后&#xff0c;返回目…

Micormeter实战

Micrometer 为基于 JVM 的应用程序的性能监测数据收集提供了一个通用的 API&#xff0c;支持多种度量指标类型&#xff0c;这些指标可以用于观察、警报以及对应用程序当前状态做出响应。 前言 可接入监控系统 监控系统的三个重要特征&#xff1a; 维度&#xff08;Dimensio…

[保姆教程] Windows平台OpenCV以及它的Golang实现gocv安装与测试(亲测通过)

一、MinGW & CMake 预备步骤 首先打开cmd: c: md mingw-w64 md cmake下载安装MinGW-W64 访问&#xff1a; https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/7.3.0/ 下载&#xff1a; MinGW-W64 GCC-8…

一文详解Softmax的性质与Self-Attention初步解析

概述 最近研究超平面排列(Hyperplane Arrangement)问题的时候&#xff0c;发现ReLU有其缺陷&#xff0c;即举例来说&#xff0c;ReLU 无法使用单一的超平面将分离的所有数据&#xff0c;完整的输出&#xff0c;即只会输出半个空间映射的数据&#xff0c;而另一半空间的数据被置…

面试---简历

项目 1.1、商品管理 新增商品 同时插入商品对应的使用时间数据&#xff0c;需要操作两张表&#xff1a;product&#xff0c;product_usetime。在productService接口中定义save方法&#xff0c;该方法接受一张Dto对象&#xff0c;dto对象继承自product类&#xff0c;并将prod…

学习open62541 --- [78] 单线程和多线程的使用场景

open62541提供多线程功能&#xff0c;默认不开启&#xff0c;即单线程&#xff0c; 把UA_MULTITHREADING的值设置为 > 100就可以开启多线程了。 这里单线程/多线程的意思是基于open62541运行的server内部是否使用锁去保护数据。只要server运行后还有读写操作需要做&#x…

从源码全面解析 dubbo 消费端服务调用的来龙去脉

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

3D 顶点着色与Phong 反射模型

Phong 反射模型有时被称为“Phong 照明”或“Phong 照明”。它由环境光照、漫反射&#xff08;朗伯反射&#xff09;、镜面反射三部分组成。 Phong 反射模型提供了一个方程式&#xff0c;用于计算表面上每个点的光照&#xff0c;I_p&#xff1a; 第一部分代表环境光项。在GLSL代…

X书hmac参数

被删重新发送 全文可以查看&#xff1a; 上面一遍unidbg解密shield文章 unidbg - 》 callObjectMethodV方法填写你的小红书路径下s.xml里的值: 或者在抓包响应头中: 查找xy-ter-str hmac 结果都是在&#xff0c;响应头里&#xff0c;所以 hmac 是服务器下发给客户端的. Over…

黑马头条.

文章目录 前言一、项目概述1.1 能收获什么1.2 项目概述1.3 项目术语1.4 业务说明 二、技术栈2.1技术栈整体框架图2.2技术栈简介 三、nacos环境搭建3.1 虚拟机镜像准备3.2 nacos的安装 四、初始工程搭建4.1 开发环境准备 五、实现登录功能5.1 需求分析5.2 表结构分析5.3 思路分析…

22道常见RocketMQ面试题以及答案

面试宝典到手&#xff0c;搞定面试&#xff0c;不再是难题&#xff0c;系列文章传送地址&#xff0c;请点击本链接。 1、RocketMQ是什么? 2、RocketMQ有什么作用&#xff1f; 3、RoctetMQ的架构 4、RoctetMQ的优缺点 8、消息过滤,如何实现&#xff1f; 9、消息去重,如果…

Elasticsearch 基本使用(四)聚合查询

聚合查询 概述单字段聚合查询统计分组后的数量非文档字段分组文档字段分组 其他聚合运算统计平均值统计总金额统计最大值自定义聚合结果排序简单聚合小结 多字段聚合查询 概述 说到聚合查询&#xff0c;马上会想到 SQL 中的 group by&#xff0c;ES中也有类似的功能&#xff0…

编程语言发展历史

文章目录 语言的发展时间轴语言世代时间轴1940年前-机器语言时代1940年后-汇编语言时代1950年-高级语言的初生1960年-高级语言的进一步成熟1980年-各大语言的进一步增强1990年代-飞速发展时代2000年-新时代 高级编程语言的分类解释型与编译型面向过程与面向对象 对语言的评价Ti…

【学习学习】NLP理解层次模型

NLP&#xff08;Neuro-Linguistic Programming&#xff0c;神经语言程序学&#xff09;&#xff0c;由两位美国人理查得.班德勒&#xff08;Richard Bandler&#xff09;与约翰.葛瑞德&#xff08;John Grinder&#xff09;于1976年创办&#xff0c;并在企业培训中广泛使用。美…

PyTorch 深度学习 || 4. 自编码网络 | Ch4.3 卷积自编码网络图像去噪

卷积自编码网络图像去噪 1. 数据的准备 先简单介绍一下训练网络使用到的图像数据集——STL10&#xff0c;该数据集可以通过torchvision.datasets模块中的STL10()函数进行下载&#xff0c;该数据集共包含三种类型数据,分别是带有标签的训练集和验证集&#xff0c;分别包含5000…

Cookie增删改查方法封装(低内存开销版)

本文章中的低内存开销是指在获取cookie的时候不进行字符串—>数组的转变&#xff0c;全程使用sliceindexOf切割字符串&#xff0c;不创建和操作数组&#xff0c;节约内存&#xff0c;本文代码已存放到github中&#xff0c;后续会持续完善功能&#xff0c;传送门&#xff1a;…

二进制方式部署kubernetes集群

二进制方式部署kubernetes集群 1、部署k8s常见的几种方式 1.1 kubeadm Kubeadm 是一个 k8s 部署工具&#xff0c;提供 kubeadm init 和 kubeadm join&#xff0c;用于快速部署 Kubernetes 集群。 Kubeadm 降低部署门槛&#xff0c;但屏蔽了很多细节&#xff0c;遇到问题很难…

掌握Python的X篇_4_开发工具ipython与vscode的安装使用

本篇将会介绍两个工具的安装及使用来提高Python的编程效率。 ipython&#xff1a;比python更好用的交互式开发环境vscode&#xff1a;本身是文本编辑器&#xff0c;通过安装相关的插件vscode可以作为python集中开发环境使用 掌握Python的X篇_4_开发工具ipython与vscode的安装使…