### 问题:如何通过 `ProceedingJoinPoint` 获取目标类的 `Class` 对象?
在 Spring AOP 中,`ProceedingJoinPoint` 是一个非常重要的接口,它允许我们在环绕通知(Around Advice)中拦截方法调用,并对方法执行进行增强。然而,在实际开发过程中,我们常常需要获取被拦截方法所在的目标类的 `Class` 对象,以便进一步操作或验证。
#### 背景
在 AOP 编程中,`ProceedingJoinPoint` 提供了丰富的信息来描述当前的连接点(Join Point)。例如,它可以通过 `getSignature()` 方法获取方法签名,通过 `getArgs()` 获取方法参数,甚至通过 `proceed()` 执行目标方法。但如果我们想获取目标类的 `Class` 对象,`ProceedingJoinPoint` 并没有直接提供这样的方法。
#### 常见的技术问题
**问题描述**:
在使用 Spring AOP 的环绕通知时,如何通过 `ProceedingJoinPoint` 获取目标类的 `Class` 对象?如果目标类是一个代理对象(如 CGLIB 或 Javassist 生成的代理),应该如何正确处理?
---
#### 解决方案
##### 方法一:通过 `ProceedingJoinPoint.getTarget()` 获取目标对象并反射其类
`ProceedingJoinPoint` 提供了一个 `getTarget()` 方法,该方法返回当前被拦截方法所属的目标对象(即实际的业务对象)。我们可以通过这个目标对象获取其 `Class` 对象。
```java
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class MyAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取目标对象
Object target = joinPoint.getTarget();
// 获取目标类的 Class 对象
Class targetClass = target.getClass();
System.out.println("目标类是:" + targetClass.getName());
// 继续执行目标方法
return joinPoint.proceed();
}
}
```
**注意**:
1. 如果目标类被代理(例如使用 CGLIB 或 JDK 动态代理),`target.getClass()` 返回的可能是代理类(如 `com.example.service.MyService$$EnhancerBySpringCGLIB$$...`),而不是原始的目标类。
2. 在这种情况下,我们需要进一步处理以获取原始类。
---
##### 方法二:通过 `AopUtils` 获取原始类
为了确保我们获取到的是原始的目标类,而不是代理类,可以借助 Spring 框架提供的工具类 `AopUtils`。`AopUtils.getTargetClass()` 方法可以帮助我们从代理对象中提取出原始的目标类。
```java
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.framework.AopProxyUtils;
@Aspect
public class MyAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取目标对象
Object target = joinPoint.getTarget();
// 使用 AopUtils 获取原始的目标类
Class targetClass = AopProxyUtils.ultimateTargetClass(target);
System.out.println("原始目标类是:" + targetClass.getName());
// 继续执行目标方法
return joinPoint.proceed();
}
}
```
**优点**:
- `AopProxyUtils.ultimateTargetClass()` 方法能够穿透代理层,直接返回原始的目标类。
- 这种方式更加可靠,特别是在复杂的代理场景下(如多层代理)。
---
##### 方法三:通过 `Signature` 获取声明类
除了通过目标对象获取类之外,我们还可以通过 `ProceedingJoinPoint.getSignature()` 方法获取方法签名,并从中提取声明类。
```java
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
@Aspect
public class MyAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取方法签名
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
// 获取声明类
Class declaringClass = methodSignature.getDeclaringType();
System.out.println("声明类是:" + declaringClass.getName());
// 继续执行目标方法
return joinPoint.proceed();
}
}
```
**注意**:
- `getDeclaringType()` 返回的是声明该方法的类,这可能与目标类不同。例如,如果目标类继承了一个父类,并且方法定义在父类中,那么 `getDeclaringType()` 返回的是父类。
- 如果需要确保获取到的是目标类而非声明类,建议结合方法一或方法二。
---
#### 总结
在 Spring AOP 中,通过 `ProceedingJoinPoint` 获取目标类的 `Class` 对象有多种方式:
1. **通过 `getTarget()` 方法获取目标对象并反射其类**:适用于简单的场景,但如果存在代理,则需要额外处理。
2. **通过 `AopUtils.getTargetClass()` 获取原始类**:推荐的方式,能够穿透代理层,直接获取原始的目标类。
3. **通过 `MethodSignature.getDeclaringType()` 获取声明类**:适用于需要知道方法声明位置的场景,但可能与目标类不同。
根据实际需求选择合适的方式,同时注意代理类的存在可能会对结果产生影响。
关注
码龄 粉丝数 原力等级 --
- 被采纳
- 被点赞
- 采纳率

ProceedingJoinPoint如何获取目标类的Class对象?
收起
- 写回答
- 好问题 0 提建议
- 关注问题
微信扫一扫
点击复制链接分享
- 邀请回答
- 编辑 收藏 删除 结题
- 收藏 举报
0条回答 默认 最新
编辑
预览

轻敲空格完成输入
- 显示为
- 卡片
- 标题
- 链接
报告相同问题?
提交
- 2024-10-19 09:382401_83288271的博客 AOP:面向特定方法编程。
- 2025-01-30 16:44kfepiza的博客 提供了一种强大的方式来...在Spring框架的面向切面编程(AOP)中,是一个关键的接口,它扩展了JoinPoint接口,并提供了控制目标方法执行流程的能力。以下是关于代表了一个正在执行的连接点,即目标方法执行时的特定点。
- 2024-04-14 08:28执键行天涯、的博客 在SpringAOP中,JoinPoint和ProceedingJoinPoint都是关键的接口,用于在切面中获取方法的相关信息以及控制方法的执行。它们的主要区别在于它们在AOP通知中的使用方式和功能。 2. JoinPoint简介 Joinpoint是面向切面...
- 2024-04-24 02:17Yeats_Liao的博客 18:面向切面编程-Java Spring
- 2024-10-08 13:03cyt涛的博客 AOP的作用:在程序运行期间在不修改源代码的基础上对已有方法进行增强(无侵入性: 解耦)AOP面向切面编程和OOP面向对象编程一样,它们都仅仅是一种编程思想,而动态代理技术是这种思想最主流的实现方式。而Spring的...
- 2024-07-29 09:55安晴晚风的博客 SpringBoot中的面向切面编程AOP
- 2025-01-30 11:22kfepiza的博客 切面类是一个用@Aspect注解标记的类,它包含了切点(pointcut)和通知(advice)。切点:定义了哪些方法将被拦截。通知:定义了拦截到方法时要执行的操作。@Aspect@Component// 定义一个切点,匹配所有...
- 2024-07-25 13:05王二空间的博客 Spring IOC 是软件组件松耦合度,而AOP让你能够捕捉系统中经常使用的功能,把它...Spring 在这两种动态代理中灵活切换,如果是代理接口,会默认使用JDK动态代理,如果要代理某个类,这个类没有实现接口,就会切换使用
- 2022-11-24 06:14杨星河的博客 简单介绍Spring的切面类使用。切入点的概念。以及操作joinPoint。
- 2025-03-09 00:15向上的车轮的博客 在面向对象编程中,我们通过继承、封装和多态解决纵向问题(如功能扩展),但。(如日志、事务、安全等)往往分散在各个类中,导致代码冗余且难以维护。• 通过 Spring 容器统一管理切面和业务对象的生命周期。的...
- 2020-11-19 16:00吴就业的博客 反应式编程虽然能提升性能,有诸多好处,却也带来一些弊端,增加代码的复杂度、高度的API侵入(相当于依赖了一个JDK)。笔者个人认为,反应式编程不适用...
- 2024-08-30 12:29CtrlCV 攻城狮的博客 ***/@Slf4j // 为当前类引入日志功能,方便打印日志信息@Component // 将当前类作为一...自动注入HttpServletRequest对象,用于获取请求信息@Autowired// 自动注入OperateLogMapper对象,用于操作数据库记录操作日志。
- 2022-05-24 02:53雅俗共赏zyyyyyy的博客 AOP(面向切面编程)作为Spring框架的两大重要特征之一,无论在日常工作还是面试中出现的频率都很高,下面从作者日常工作中的应用和学习来详细解析一下AOP。 一、AOP是什么? 面向切面编程,通过预编译方式和运行...
- 2020-11-04 02:27五岁能抬头1995的博客 Spring AOP编程 第一章 静态代理设计模式 1.1 为什么需要代理设计模式 在JavaEE分层开发中,最为重要的是Service层。 Service层中包含了哪些代码?...概念:通过代理类,为原始类(目标类)增加额外的功能。 好处:利
- 2024-08-30 11:27ღ᭄ꦿ࿐Never say never꧂的博客 AOP面向切面编程
- 2021-07-04 15:37多氯环己烷的博客 1.3 约定编程Spring AOP前言1.2.3.最后 前言 1. 2. 3. 最后 新人制作,如有错误,欢迎指出,感激不尽! 欢迎关注公众号,会分享一些更日常的东西! 如需转载,请标注出处!
- 2025-03-20 13:46qq_53604925的博客 AOP面向方法编程,可以做到在不改动这些原始方法的基础上,针对特定的方法进行功能的增强。这个流程与动态代理技术是非常类似的。代理对象中的方法以及根据对应的业务需要, 完成了对应的业务功能,当运行原始业务...
- 2025-01-22 15:16姜767的博客 自定义注解允许你在 Java 代码中创建自己的注解类型,它们可以用来为程序元素(如类、方法、字段等)添加元数据。使用@interface关键字来定义一个注解。例如:java// 定义注解的作用范围,这里表示该注解可以应用于...
- 2018-11-09 03:39cyh90的博客 AOP 面向切面编程 、 JdbcTemplete 工具类使用 目录 一、 什么是 AOP ***** 二、 AOP 的底层实现 1、 JDK动态代理 2、 使用CGlib 完成动态代理 三、 Spring AOP 1、 传统Spring AOP 提供 五类 Advice 2、 ...
- 2020-03-31 14:35abormrsf的博客 面向切面的编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象的编程(OOP)。 阅读Spring官方文档,梳理一下SpringAOP知识点 原文地址:https://blog.cayzlh.com/archives/741621cd.html OOP中模块化的...
- 没有解决我的问题, 去提问