如果对于spring MethodInterceptor或spring aop概念不清楚,参考:spring aop, spring interceptor, springmvc interceptor有什么区别?
以下是在spring boot环境下执行的
在spring boot下有两种方式设置AOP(实现织入weave):
1. 使用@Aspect注解
2. 使用DefaultPointcutAdvisor
以实现TracingInterceptor为例
interceptor
class TracingInterceptor implements MethodInterceptor {
Object invoke(MethodInvocation i) throws Throwable {
System.out.println("method "+i.getMethod()+" is called on "+
i.getThis()+" with args "+i.getArguments());
Object ret=i.proceed();
System.out.println("method "+i.getMethod()+" returns "+ret);
return ret;
}
}
织入配置类
@Configuration
public class InterceptorConfig {
public static final String traceExecution = "execution(* com.hfi.aop..*.*(..))";
@Bean
public DefaultPointcutAdvisor defaultPointcutAdvisor2() {
TracingInterceptor interceptor = new TracingInterceptor();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(traceExecution);
// 配置增强类advisor
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
advisor.setPointcut(pointcut);
advisor.setAdvice(interceptor);
return advisor;
}
}
效果:当执行到com.hfi.aop包下的方法,当执行performEncore方法
可以看到我们配置的TracingInterceptor生效了
自定义注解HfiTrace
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HfiTrace {
}
interceptor
public class TracingInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
HfiTrace annotation = getAnnotation(method);
if (annotation == null) {
return invocation.proceed();
}
// 为什么调用http://127.0.0.1:8089/jpademo/perform时有两次输出呢?
// 因为在Audience里面用的是@Around,会拦截到两次
System.out.println("method " + invocation.getMethod() + " is called on " + invocation.getThis() + " with args" +
" " + invocation.getArguments());
Object proceed = invocation.proceed();
System.out.println("method " + invocation.getMethod() + " returns " + proceed);
return proceed;
}
private HfiTrace getAnnotation(Method method) {
// 如果有多个annotation 似乎就不好用了 如放在controller上 由于已经有了@RequestMapping注解了 所以...
if (method.isAnnotationPresent(HfiTrace.class)) {
return method.getAnnotation(HfiTrace.class);
}
return null;
}
}
织入配置类
@Configuration
public class InterceptorAnnotationConfig {
@Bean
public DefaultPointcutAdvisor defaultPointcutAdvisor3() {
TracingInterceptor interceptor = new TracingInterceptor();
// AnnotationMatchingPointcut pointcut = new AnnotationMatchingPointcut(HfiTrace.class, true);
JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
pointcut.setPatterns("com.hfi.*");
// 配置增强类advisor
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
advisor.setPointcut(pointcut);
advisor.setAdvice(interceptor);
return advisor;
}
}
业务代码
@HfiTrace
@Override
public String perform() {
System.out.println("perform...");
return "perform";
}
效果:
可以看到执行也是生效的
自定义注解HfiTrace
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HfiTrace {
String name() default "默认注解信息";
}
织入配置类
@Component
@Aspect
public class TracingAspect {
@Before("@annotation(test)")
public void beforeTest(JoinPoint point, HfiTrace test){
System.out.println("method " + point.getSignature().getName() + " is called on " + point.getThis() + " with " +
"args" +
" " + point.getArgs());
System.out.println("before invoke: "+ test.name());
}
@AfterReturning(value = "@annotation(test)", returning = "rvt")
public void afterTest(JoinPoint point, HfiTrace test, Object rvt) {
System.out.println("method "+point.getSignature().getName() + " returns " + rvt);
System.out.println("after invoke: " + test.name());
}
}
业务代码:
controller层:
@HfiTrace
@GetMapping("/perform")
public String perform() {
String perform = performance.perform();
return perform;
}
@HfiTrace(name = "abc")
@GetMapping("/performEncore")
public String performEncore() {
// 强制转换
Encoreable encoreable = (Encoreable) performance;
return encoreable.performEncore();
}
service层:
@Component
public class PerformanceImpl implements Performance {
@HfiTrace
@Override
public String perform() {
System.out.println("perform...");
return "perform";
}
}
效果:
综上:三种方式都可以实现相同的功能,方法3看起来最为简洁,只需要定义一个注解,然后写一个@Aspect切面类,就可以拦截指定方法的运行了
源代码:https://gitee.com/constfafa/spring_springboot_learning/tree/master/methodinterceptor-demo