AOP实现拦截对象以及获取切入目标方法和注解

本文介绍了AspectJ中JoinPoint接口及其子接口ProceedingJoinPoint的使用方法,详细阐述了如何利用这些接口获取目标方法的参数、签名及目标对象等信息,并提供了三种获取切入点目标方法的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

AOP实现拦截对象以及获取切入目标方法和注解

 

一、JoinPoint是什么?

  AspectJ使用org.aspectj.lang.JoinPoint接口表示目标类连接点对象,如果是环绕增强时,使用 org.aspectj.lang.ProceedingJoinPoint表示连接点对象,该类是JoinPoint的子接口。任何一个增强方法都可以 通过将第一个入参声明为JoinPoint访问到连接点上下文的信息。

 

二、我们先来了解一下这两个接口的主要方法

1.JoinPoint 
l java.lang.Object[] getArgs():获取连接点方法运行时的入参列表; 
l Signature getSignature() :获取连接点的方法签名对象; 
l java.lang.Object getTarget() :获取连接点所在的目标对象; 
l java.lang.Object getThis() :获取代理对象本身;

 

2.ProceedingJoinPoint 

  ProceedingJoinPoint继承JoinPoint子接口,它新增了两个用于执行连接点方法的方法:

  java.lang.Object proceed() throws java.lang.Throwable:通过反射执行目标对象的连接点处的方法; 

  java.lang.Object proceed(java.lang.Object[] args) throws java.lang.Throwable:

  通过反射执行目标对象连接点处的方法,不过使用新的入参替换原来的入参。 

 

三、再了解一下JoinPoint接口的子接口和实现类:

 

四、获取切入方法对象三种方法:

 

1.通过反射机制获取切入点目标类的方法

public void invoke(JoinPoint joinPoint) throws Throwable{

//登录拦截

MethodInvocationProceedingJoinPoint methodPoint = (MethodInvocationProceedingJoinPoint)joinPoint;

Field proxy = methodPoint.getClass().getDeclaredField("methodInvocation");

proxy.setAccessible(true);

ReflectiveMethodInvocation j = (ReflectiveMethodInvocation) proxy.get(methodPoint);

Method method = j.getMethod();

Login login = method.getAnnotation(Login.class);

}


 

 

2.通过JoinPoint的getTarget()获取连接点所在的目标对象

 

public void invoke(JoinPoint joinPoint) throws Throwable{

//拦截的实体类

Object target = joinPoint.getTarget();

//拦截的方法名称

String methodName = joinPoint.getSignature().getName();

//拦截的方法参数

Object[] argsa = joinPoint.getArgs();

//拦截的放参数类型

Class[] parameterTypes = ((MethodSignature)joinPoint.getSignature()).getMethod().getParameterTypes();

Method method = target.getClass().getMethod(methodName, parameterTypes);

Login login = method.getAnnotation(Login.class);

}


 

3.通过JoinPoint的getSignature()获取连接点的方法签名对象

public void invoke(JoinPoint joinPoint) throws Throwable{

MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();

Method method = methodSignature.getMethod();

Login login = method.getAnnotation(Login.class);

}


<think>好的,我现在需要帮助用户解决如何使用AOP拦截所有实现相同接口的类的方法的问题。首先,我得理解用户的需求。用户提到他们已经有了使用拦截Redis进行接口访问限制的例子,还提到了Spring AOP实现重复触发拦截。现在他们想扩展这个功能,通过AOP拦截所有实现同一接口的类的方法,并希望看到示例代码。 首先,我需要回忆一下Spring AOP的相关知识。AOP(面向切面编程)通常通过切点表达式来定义哪些方法需要被拦截。用户需要拦截的是所有实现某个特定接口的类的方法。因此,切点表达式应该匹配那些实现目标接口的类中的方法。 接下来,我需要确定如何编写这样的切点表达式。在Spring AOP中,可以使用`execution`表达式来指定方法执行的点。要匹配实现某个接口的所有类,可能需要使用`within`表达式或者`target`表达式。比如,`target(com.example.MyInterface)`会匹配所有实现了MyInterface接口的目标对象方法。不过需要注意,Spring AOP默认是基于代理的,对于接口的代理使用的是JDK动态代理,而类则使用CGLIB。因此,如果目标实现了接口,Spring会优先使用JDK代理,否则用CGLIB。这可能影响切点的匹配方式。 然后,我需要考虑如何定义切面。用户需要一个@Around建议,这样可以在方法执行前后添加逻辑。同时,可能需要自定义一个注解,比如@DistinctRequest,来标记需要拦截方法,或者直接在切点中指定接口。 示例代码的结构大致如下:首先定义一个注解(如果需要),然后编写切面类,使用@Aspect@Component注解,定义切点表达式,并编写通知方法。例如,切点表达式可能是`execution(* com.example.MyInterface.*(..))`,这样会匹配MyInterface接口中所有方法的所有实现。 不过,用户可能希望更灵活地拦截所有实现某个接口的类,而不仅仅是显式调用接口方法的情况。这时候可能需要使用`target`表达式,比如`target(com.example.MyInterface)`,这样所有实现该接口的类的所有方法都会被拦截,无论它们是否在接口中声明。但需要注意,这可能会拦截到更多的方法,包括那些在子类中新增的方法,而不仅仅是接口中的方法。 然后,在通知方法中,用户可能需要获取方法签名、参数等信息,以便进行后续处理,比如限流、日志记录等。例如,可以使用ProceedingJoinPoint来获取方法的信息,并决定是否继续执行方法。 另外,还需要考虑Spring AOP的局限性,比如只能拦截Spring管理的bean的方法,对于非Spring管理的对象无效。此外,自调用(即同一个类中的一个方法调用另一个方法)不会被AOP拦截,因为这是通过代理实现的。 在代码示例中,可能需要包括定义切面类、切点表达式、通知方法,以及可能的自定义注解。例如,用户可能希望某些方法拦截,或者根据注解参数进行不同的处理,如设置过期时间等。 最后,需要验证示例代码的正确性,确保切点表达式正确匹配目标方法,并且通知逻辑能够按预期执行。可能还需要测试不同的场景,比如不同的实现类、不同的方法签名等,确保拦截正确无误。 总结一下,步骤大致是:确定切点表达式,定义切面类,编写通知方法,处理拦截逻辑,并考虑Spring AOP的注意事项。然后,将这些内容整理成用户容易理解的示例代码,并解释关键部分,确保用户能够根据示例实现自己的需求。</think>### 使用AOP拦截实现同一接口的所有类方法 #### 1. 定义接口实现类 假设需要拦截所有实现`DataService`接口的类方法: ```java public interface DataService { String processData(String input); } // 实现类A @Service public class DataServiceImplA implements DataService { @Override public String processData(String input) { return "Processed by A: " + input; } } // 实现类B @Service public class DataServiceImplB implements DataService { @Override public String processData(String input) { return "Processed by B: " + input; } } ``` #### 2. 定义切面类 通过`@Pointcut`表达式匹配所有实现`DataService`接口的类方法: ```java @Aspect @Component public class InterfaceAspect { // 切入点表达式:拦截所有实现DataService接口的类方法 @Pointcut("target(com.example.service.DataService)") public void interfaceMethods() {} // 环绕通知 @Around("interfaceMethods()") public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); String methodName = signature.getMethod().getName(); System.out.println("拦截方法: " + methodName); Object result = joinPoint.proceed(); System.out.println("方法执行完成"); return result; } } ``` #### 3. 技术要点说明 1. **切点表达式**: - `target(com.example.service.DataService)`表示拦截所有实现该接口的类实例的方法 - 若需精确控制方法范围,可组合使用`execution`表达式: $$@Pointcut("execution(* com.example.service.DataService.*(..))")$$[^2] 2. **代理方式选择**: - 若目标类未实现接口,需强制使用CGLIB代理: $$@EnableAspectJAutoProxy(proxyTargetClass = true)$$[^2] 3. **获取方法信息**: ```java Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); Object[] args = joinPoint.getArgs(); ``` #### 4. 扩展应用场景 可结合自定义注解实现更细粒度的控制: ```java @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ApiMonitor { int timeout() default 1000; } ``` 在切面中组合使用注解过滤: ```java @Pointcut("@annotation(com.example.annotation.ApiMonitor)") public void annotatedMethods() {} @Around("interfaceMethods() && annotatedMethods()") public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable { // 性能监控逻辑 } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值