为下一篇日志链路追踪做铺垫先了解下AOP,这一块我就不用从新写了 基本可以看看这一篇
原文链接:https://blog.csdn.net/u013905744/article/details/91364736
如果对于spring MethodInterceptor或spring aop概念不清楚,参考:spring aop, spring interceptor, springmvc interceptor有什么区别?
以下是在spring boot环境下执行的
在spring boot下有两种方式设置AOP(实现织入weave):
1. 使用@Aspect注解
2. 使用DefaultPointcutAdvisor
以实现TracingInterceptor为例
方法1:使用aspectj execution(切点) + interceptor(增强Advice)构成织入(DefaultPointcutAdvisor)
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生效了
方法2:使用自定义注解(切点)+interceptor(增强Advice)构成织入(DefaultPointcutAdvisor)
自定义注解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";
-
}
效果:
可以看到执行也是生效的
方法3:使用自定义注解(切点)+@Aspect(切面)构成织入
自定义注解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切面类,就可以拦截指定方法的运行了