问题
由于业务上的需求,我们需要对标注了 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 实现该功能
- 首先自己新增一个 advisor 类,内部携带了切点的实现
- 新增 MethodInterceptor 通知类,实现增强逻辑
- 将两者组合,放入 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 匹配规则