MethodInterceptor 的几种用法

Image by Michel van der Vegt from Pixabay

前言

最近在看springboot@EnableAsync的源码,发现还是需要提前看一些东西,比如这次的MethodInterceptor接口的作用;如今springboot都到2.0以后了,我谷歌出来好多文章都是用的配置文件,本篇就用纯代码的形式来说明MethodInterceptor的用法;

正文

项目使用springboot的2.3.0.RELEASE版本构建,其中需要注意导入aopstarter

1
2
3
4
5
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        

注意:springboot项目中若未加入上面的包,案例一会报错,案例二不会报错,但是不会生效;

非注解

以下两个案例都是针对非注解的

案例一

使用aspectj execution表达定义切点;这个就比较灵活了,主要就是看traceExecution怎么去写了;

  1. 自己写一个类实现MethodInterceptor接口的invoke()方法
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9

public class MyInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println(methodInvocation.getMethod().getName());
        return methodInvocation.proceed();
    }
}

  1. 使用 AspectJExpressionPointcut定义切点并注册
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

@Configuration
public class InterceptorConfig {
   //注意该地址为项目具体包地址
   public static final String traceExecution = "execution(* com.example.methodinterceptor..*.*(..))";
   @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor2() {
        MyInterceptor interceptor = new MyInterceptor();
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(traceExecution);

        // 配置增强类advisor
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        advisor.setAdvice(interceptor);
        return advisor;
    }
}

案例二

这个案例主要是用JdkRegexpMethodPointcut来构造切点,这个就看Pattern参数怎么写了;

  1. 自己写一个类实现MethodInterceptor接口的invoke()方法
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9

public class MyInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println(methodInvocation.getMethod().getName());
        return methodInvocation.proceed();
    }
}

  1. 使用 JdkRegexpMethodPointcut定义切点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

@Configuration
public class InterceptorConfig {
     @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor() {
        JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
        pointcut.setPattern("com.example.methodinterceptor.*");
        // 配置增强类advisor
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        advisor.setAdvice(new MyInterceptor());
        System.out.println(advisor.toString());
        return advisor;
    }
}

注解

  1. 自定义注解
1
2
3
4
5
6
7

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface InterceptorAnnotation {
}

案例三

这个案例就是案例一,只是将AspectJExpressionPointcut的参数改变了Expression;
直接使用案例一代码,然后将traceExecution修改就可以了

1
2
3

public static final String traceExecution = "annotation(com.example.methodinterceptor.annotation.InterceptorAnnotation)";

案例四

这个案例就是使用AnnotationMatchingPointcut来构造切点;

  1. 自己写一个类实现MethodInterceptor接口的invoke()方法
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9

public class MyInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println(methodInvocation.getMethod().getName());
        return methodInvocation.proceed();
    }
}

  1. 使用AnnotationMatchingPointcut构造切点

注意: 这是使用的AnnotationMatchingPointcut构造方法;在参考文章1中使用的是:

1
2
3

AnnotationMatchingPointcut pointcut = new AnnotationMatchingPointcut(InterceptorAnnotation.class, true);

这个写法并没有对该注解进行拦截;在文章末尾的评论有提到这个问题;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

@Configuration
public class InterceptorConfig {
     @Bean
    public Advisor pointcutAdvisor() {
        MyInterceptor interceptor = new MyInterceptor();

        AnnotationMatchingPointcut pointcut = new AnnotationMatchingPointcut(null,InterceptorAnnotation.class);
        // 配置增强类advisor
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        advisor.setAdvice(interceptor);
        System.out.println(advisor.toString());
        return advisor;
    }
}

总结

以上几种案例感觉能满足很多场景了,但是感觉每种场景都有很多案例支持,具体却不知道选取哪一种,只有多看看源码,去了解思想了;

最后

项目地址:
文章地址:

我的二维码:
我的二维码

参考:

  1. 使用spring的MethodInterceptor实现aop功能的三种方式
  2. 透过现象看原理:详解Spring中Bean的this调用导致AOP失效的原因
  3. Java AnnotationMatchingPointcut类代码示例
坚持原创技术分享,您的支持将鼓励我继续创作!