Spring AOP 切面匹配父类或接口上的注解

问题

由于业务上的需求,我们需要对标注了 RPC 注解的接口进行代理,对所有接口方法的参数做前置处理。

// 接口中标注了 Rpc 注解,希望他的实现类的接口方法都能得到增强
@Rpc
public interface OneService {
	// 需要对这个方法做增强
    void foo();
}

但是没有预设的拦截器,对标注Rpc注解的类做增强,普通的 Aspect 注解只能在方法上标记注解增强,如果不在方法上标记,则无法增强

@Slf4j
@Aspect
@Component
public class MyAop {
    /**
     * 无法匹配到上面的 foo 方法
     */
    @Before(value ="@annotation(com.aop.Rpc)")
    public void before1(JoinPoint joinPoint){
        // do something...
    }
}

解决方法

Spring 提供的 Aspect 切面注解无法实现,但是可以通过底层的 Advisor 实现该功能

  1. 首先自己新增一个 advisor 类,内部携带了切点的实现
  2. 新增 MethodInterceptor 通知类,实现增强逻辑
  3. 将两者组合,放入 Spring 容器中,即可实现该功能

Advisor 源码:

public class AnnotationInheritAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {

    private final Advice advice;

    private final Pointcut pointcut;

    private final Class<? extends Annotation> annotation;

    public AnnotationInheritAdvisor(@NonNull MethodInterceptor advice,
                                              @NonNull Class<? extends Annotation> annotation) {
        this.advice = advice;
        this.annotation = annotation;
        this.pointcut = buildPointcut();
    }

    @Override
    public Pointcut getPointcut() {
        return this.pointcut;
    }

    @Override
    public Advice getAdvice() {
        return this.advice;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        if (this.advice instanceof BeanFactoryAware) {
            ((BeanFactoryAware) this.advice).setBeanFactory(beanFactory);
        }
    }

    private Pointcut buildPointcut() {
        // 匹配类上带有对应注解
        Pointcut cpc = new AnnotationMatchingPointcut(annotation, true);
        // 匹配方法上带有对应注解
        Pointcut mpc = new AnnotationMatchingPointcut(null, annotation, true);
        // 两者有其中之一符合即为真
        return new ComposablePointcut(cpc).union(mpc);
    }
}

MethodInterceptor 通知增强类

public class RpcInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object[] arguments = invocation.getArguments();
        for (Object arg : arguments) {
            // do something for args
        }
        // 执行实际的方法
        return invocation.proceed();
    }
}

在 Spring 容器配置类中新增 Advisor bean

@Bean
public Advisor rpcAdvisor() {
    RpcInterceptor interceptor = new RpcInterceptor();
    return new AnnotationInheritAdvisor(interceptor, Rpc.class);
}

原理分析

在 Spring 中,使用 Aspect 注解会在 ReflectiveAspectJAdvisorFactory 类中将标注了 Aspect 注解的类进行解析,将切点与增强逻辑转换为 PointCut(切点)和 Advice(通知),然后再将两者组成 Advisor(切面)
Aspect 所生成的 PointCut 必须要匹配到方法,无法匹配到类上或者父接口上的注解,因此我们只需要自己实现一个切面就可以了

切面类图

在这里插入图片描述

Aspect 切面匹配图

对应问题中的 Aspect 注解标注的类

自定义 Advisor 匹配图

自定义的 Advisor 匹配规则

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值