SpringAop之joinPoint讲解

article/2025/9/14 9:34:49

一、学习背景

摸鱼的时候继续复刻demo,没错,同之前一篇文章,在写aop时又发现自己对aop只停留在面试阶段,甚至还不如,完全不会实践,所以在此记录复刻aop用到的的一些且自己已经遗忘的知识。
那么复刻的一个需求点我以最简单来说对于此次要学习的内容:就是通过joinPoint获取方法上的特定注解。
注解代码如下:

import com.uum.common.core.enums.BusinessType;import java.lang.annotation.*;/*** 自定义注解--操作日志记录*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Operation {/*** 模块*/String description() default "";/*** 功能*/BusinessType businessType() default BusinessType.OTHER;/*** 是否保存请求的参数*/boolean isSaveRequestData() default true;/*** 是否保存返回结果*/boolean isSaveResponseData() default true;
}

那么这个就是系统操作日志的注解,主要到时候用aop的joinPoint获取标注在方法上该注解联合方法的相关内容将其转化为系统日志并进行存储。那么问题来了,什么是joinPoint?

二、joinPoint对象

2.1、joinPoint

  • 在AOP中,我们知道描述切面的术语有通知(advice),切点(pointcut),连接点(join point)
  • 连接点(joinPoint)就是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。
  • 这个类的主要作用就是可以让我们在Advice中获取被增强方法相关的所有信息。通过JoinPoint可以获取被代理方法的各种信息,如方法参数,方法所在类的class对象,然后执行反射操作
    它的主要方法及相关解释如下表格:
方法名功能
Signature getSignature();获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息
Object[] getArgs();获取传入目标方法的参数对象
Object getTarget();获取被代理的对象
Object getThis();获取代理对象
其中关键方法就是这个getSignature(),该方法返回Signature对象,而通过该对象我们可以获得被增强方法的信息。

2.2、ProceedingJoinPoint

ProceedingJoinPoint继承JoinPoint,是它的子接口,在joinPoint的基础上对其增强功能。其实主要是在JoinPoint的基础上暴露出 proceed 这个方法。proceed很重要,这个是aop代理链执行的方法。

public interface ProceedingJoinPoint extends JoinPoint {  public Object proceed() throws Throwable;  public Object proceed(Object[] args) throws Throwable;  } 

环绕通知=前置+目标方法执行+后置通知,proceed方法就是用于启动目标方法执行的

  • 暴露出这个方法,就能支持 aop:around 这种切面(而其他的几种切面只需要用到JoinPoint,,这也是环绕通知和前置、后置通知方法的一个最大区别。这跟切面类型有关), 能决定是否走代理链还是走自己拦截的其他逻辑。建议看一下 JdkDynamicAopProxy的invoke方法,了解一下代理链的执行原理。
  • 注:ProceedingJoinPoint is only supported for around advice
  • 典型的用法如下:
 public Object around(ProceedingJoinPoint point) throws Throwable {Signature signature = point.getSignature();// AopUtils.getTargetClass(point.getTarget())获取原始对象,例如对于Mapper而言,它获取的是具体代理的Mapper如com.b.mapper.DefaultDsMapper(如果前者继承了后者的话)而不是定义该方法的Mapper如com.b.base.BaseMapper<Info, InfoExample, InfoKey>,如下图Type[] types = AopUtils.getTargetClass(point.getTarget()).getGenericInterfaces(); // getGenericInterfaces方法能够获取类/接口实现的所有接口Annotation nologgingAnno = ((Class)types[0]).getAnnotation(Nologging.class); // type是所有类型的父接口MethodSignature methodSignature = (MethodSignature)signature;Method targetMethod = methodSignature.getMethod();}

三、Signature对象

3.1、Signature

此接口通常用于跟踪或记录应用程序以获取有关连接点的反射信息,下面是官方给的一个使用的例子

 aspect Logging {Logger logger = Logger.getLogger("MethodEntries");before(): within(com.bigboxco..*) && execution(public * *(..)) {Signature sig = thisJoinPoint.getSignature();logger.entering(sig.getDeclaringType().getName(),sig.getName());}}

源码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.aspectj.lang;public interface Signature {String toString();//返回此签名的缩写字符串表示形式String toShortString();//返回此签名的扩展字符串表示形式String toLongString();//返回此签名的标识符部分。对于方法,这将返回方法名称。String getName();//返回表示为 int 的此签名上的修饰符。使用 java.lang.reflect.Modifier 上定义的常量和辅助方法来操作它,// 检查此签名是否公开 java.lang.reflect.Modifier.isPublic(sig.getModifiers());//  打印出修饰符 java.lang.reflect.Modifier.toString(sig.getModifiers());int getModifiers();//返回一个 java.lang.Class 对象,表示声明此成员的类、接口或方面。对于成员内声明,这将是声明成员的类型,而不是按词法写入声明的类型。使用 SourceLocation.getWithinType() 获取在词法上出现声明的类型。//为了与 java.lang.reflect.Member 保持一致,这个方法应该被命名为 getDeclaringClass()Class getDeclaringType();//返回声明类型的完全限定名称。这等效于调用 getDeclaringType().getName(),但是为了更高的效率缓存了结果String getDeclaringTypeName();
}

HttpClient请求

GET http://localhost:8080/test/testAnno?name=Indian frends
Accept: application/json

运行结果

I'm fine ,thank you
toString; String com.mz.testSpring.controler.testSpringControler.sayHello(String)
toShortString; testSpringControler.sayHello(..)
toLongString; public java.lang.String com.mz.testSpring.controler.testSpringControler.sayHello(java.lang.String)
getName; sayHello
getModifiers; 1
getDeclaringType; com.mz.testSpring.controler.testSpringControler
getDeclaringTypeName; com.mz.testSpring.controler.testSpringControler

可以看出,Signature 也是为了获取原始方法的各种信息而存在的,并且信息更加的简洁,方便我们截取,他与JoinPoint合作可以让我们更方便的获取原始方法的各种信息

3.2、MethodSignature

当然我们通过Signature上面的方法还是不能很方便达成我们获取方法上的注解等操作。因为我们获取不了方法本身这个Method类。
那么这时MethodSignature就出现了,顾名思义,它就是方法签名,可以看下它的源码:

public interface MethodSignature extends CodeSignature {Class getReturnType();      /* name is consistent with reflection API */Method getMethod();
}

它就提供了两个方法,其中关键点就在于getMethod()方法,它可以获取被增强的方法本身Method这个类,通过该类就类似反射操作了,可以通过它的API完成获取注解等操作。
那怎么通过Signature得到MethodSignature呢
其实很简单,可以看一下它的依赖关系图:
在这里插入图片描述
所以你应该就明白了,强转即可。
那么我们就可以完成通过Signature获取注解的操作,方法如下:

 private Optional<Operation> getAnnotationLog(JoinPoint joinPoint) {MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();Method method = methodSignature.getMethod();if(method != null){return Optional.ofNullable(method.getAnnotation(Operation.class));}return Optional.empty();}

四、参考链接

https://blog.csdn.net/M_amazing/article/details/121747188
https://blog.csdn.net/qq_46940224/article/details/125960508
https://blog.csdn.net/qq_15037231/article/details/80624064


http://chatgpt.dhexx.cn/article/Z8rftHcm.shtml

相关文章

SpringAOP详细配置与使用

目录 SpringAOP简介 AOP概念 Spring AOP简单流程图 Spring AOP之Annotation 前置通知(Before advice) 返回后通知(After reurning advice) 抛出异常后通知(After throwing advice) 后置通知(After (finally) advice) 环绕通知(Around advice) 引入(Introduction) Sp…

SpringAOP的注解形式

铁子们&#xff0c;快扫码关注啦&#xff01;或 wx搜索&#xff1a;“聊5毛钱的java”&#xff0c;关注可领取博主的Java学习视频资料&#xff0c;保证都是干货 上一篇讲了配置文件形式的SpringAOP&#xff1a;Spring中的AOP以及切入点表达式和各种通知 本篇继续看一下注解形…

Spring AOP超详细解析

AOP - 面向切面编程&#xff08;Aspect Oriented Programming&#xff09; Spring早期版本的核心功能&#xff1a;管理对象生命周期与对象分配。 即Bean本身的管理创建&#xff0c;以及它整个生命周期里跟其他对象相互之间引用装配 为了更好的实现管理和装配&#xff0c;一个…

Spring学习:AOP概述

一、AOP概念 AOP是指面向切面编程&#xff0c;利用 AOP 可以对业务逻辑的各个部分进行隔离&#xff0c;从而使得业务逻辑各部分之间的耦合度降低&#xff0c;提高程序的可重用性&#xff0c;同时提高了开发的效率。 通俗描述&#xff1a;不通过修改源代码方式&#xff0c;在主干…

SpringAOP学习--SpringAOP简介及原理

前文对AOP做了介绍&#xff0c;实际项目中&#xff0c;一般不会直接上手手动实现aop&#xff0c;而是使用一些高级封装的aop实现&#xff0c;如SpringAOP。 Spring是一个广泛应用的框架&#xff0c;SpringAOP则是Spring提供的一个标准易用的aop框架&#xff0c;依托Spring的IOC…

图文详解Spring AOP,你学会了吗?

如果说 IOC 是 Spring 的核心&#xff0c;那么面向切面编程AOP就是 Spring 另外一个最为重要的核心&#xff0c;需要重点掌握mikechen 本篇主要会详解以下六点&#xff1a; 1.AOP的定义 2.AOP的作用 3.AOP的应用场景 4.Spring AOP的术语 AOP核心概念Spring AOP 通知分类S…

Spring AOP全面详解(超级详细)

如果说IOC 是 Spring 的核心&#xff0c;那么面向切面编程AOP就是 Spring 另外一个最为重要的核心mikechen AOP的定义 AOP &#xff08;Aspect Orient Programming&#xff09;,直译过来就是 面向切面编程,AOP 是一种编程思想&#xff0c;是面向对象编程&#xff08;OOP&…

mysql执行SQL脚本

方法一 【Mysql的bin目录】\mysql –u用户名 –p密码 –D数据库<【sql脚本文件路径全名】 示例&#xff1a; 如果mysql配了全局变量&#xff0c;就不需要到Mysql的bin目录下执行&#xff0c;可以在任何地方使用用户名、密码、指定数据库等参数值与参数名不需要隔空格 不…

SpringBoot 实现SQL脚本自动执行

SpringBoot 实现配置SQL脚本自动执行 一. 背景 我们可能遇到过这种情况: 在公网开发时, 新增数据表非常容易, 直接登录到对应服务器的mysql / 使用Navicat访问mysql服务器. 然后去执行sql语句或脚本即可在内网开发时, 由于都在一个网段, 所以操作也比较方便但是在公网开发, 部…

flink-sql-client提交sql脚本文件

标题: flink-sql-client提交sql脚本文件 日期: 2021-10-22 22:11:34 标签: [flink,sql-client] 分类: flink 我们知道&#xff0c;sql-client.sh可以提供给我们一个sql交互界面&#xff0c;让我们没执行一个sql&#xff0c;就可以看到执行结果&#xff0c;也可以交互式查询表的…

如何在mysql中执行sql脚本文件

一、sql脚本文件 简介 xxxx.sql这种文件被称为sql脚本文件。sql脚本文件中编写了大量的sql语句。我们执行sql脚本文件的时候&#xff0c;该文件中所有的sql语句会全部执行&#xff01;批量的执行SQL语句&#xff0c;可以使用sql脚本文件。 上面这个vip.sql就是sql脚本文件&am…

使用sql脚本创建数据库表

准备脚本语句&#xff1a; CREATE TABLE test (title varchar(100) DEFAULT NULL,author varchar(10) DEFAULT NULL,digest varchar(255) DEFAULT NULL,content text,content_source_url varchar(500) DEFAULT NULL,thumb_media_id varchar(255) DEFAULT NULL,need_open_comme…

PowerDesigner生成Sql脚本

点击工具栏上的“Database”&#xff0c;选择“Change Current DBMS”进行修改导出脚本类型&#xff0c;可以选择mysql、sql server/ oracle 、db2等主流的数据库。 在DBMS中点击下拉菜单&#xff0c;选择要导出的数据库脚本&#xff0c;对名字进行自定义&#xff0c;点击确定即…

PowerDesigner导入sql脚本

一个好的数据库建模,不但可以让人直观的理解模型,充分的利用数据库技术,优化数据库的设计,而且还可以让新员工快速的熟悉数据库表结构与业务之间的关系.无奈的是随着开发过程中,数据库表结构字段的增删以及关联关系的变动给数据库模型带来维护上的巨大工作量.现为了维护上的简单…

dbeaver导入sql脚本

新建数据库 执行脚本 选择脚本文件 选择mysql 然后按确定就行了

springboot + mybatis启动时执行sql脚本

目录 1. 创建数据版本表&#xff0c;结构如下&#xff1a; 2. 创建HdVersion对象 3. 创建执行sql的dao 4. 创建dao对应的xml 5.创建sql执行器&#xff0c;实现ApplicationRunner 6. 结语 背景&#xff1a;项目开发或发布阶段修改表结构&#xff0c;项目更新时需要手动执行脚…

SpringBoot启动自动执行sql脚本

在开发当中我们每次发布服务都需要手动执行脚本&#xff0c;然后重启服务&#xff0c;而SpringBoot有服务启动自动执行sql脚本的功能的&#xff0c;可以为我们省去手动执行脚本的这一步&#xff0c;只需要部署新的服务即可。 这个功能是SpringBoot自带的不需要引入额外的依赖&a…

Excel数据转化为sql脚本

在实际项目开发中&#xff0c;有时会遇到客户让我们把大量Excel数据导入数据库的情况。这时我们就可以通过将Excel数据转化为sql脚本来批量导入数据库。 1 在数据前插入一列单元格&#xff0c;用来拼写sql语句。 具体写法&#xff1a;"insert into t_student (id,name,ag…

MySQL导出sql脚本文件

⭐️前言⭐️ sql脚本文件在我们做项目时&#xff0c;特别是学习别人的开源项目时经常需要进行导入导出操作&#xff0c;才能在自己的系统上跑起来&#xff0c;这篇文章主要介绍如何导出sql脚本文件&#xff0c;具体操作如下&#xff0c;附带截图详解。 &#x1f349;博客主页…

dataGrip导出sql脚本

1.打开dataGrip。 2.选择要导出的数据库表。 3.点击右键->选择"Dump Data to File(s)", 同时选择&#xff0c;Skip Computed Columns(sql),Add Table Definition(sql),Overwrite Exsting Files和Single File。 4.点击sql Inserts 5.选择文件保存位置 6.生成sql脚…