偶遇 AOP 失效之类内调用

2019/11/16 BackEnd Spring

不遇不知道,一遇吓一跳。

起因

利用 AOP 切面,记录审计日志。

经过

定义注解

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

实现切面

@Aspect
@Component
@Slf4j
public class AopInvalidAspect {

  @Pointcut("execution(@org.shaneking.demo.aop.ivd.annotation.AopInvalidAnno * *..*.*(..))")
  private void pointcut() {
  }

  @Around("pointcut() && @annotation(aopInvalidAnno)")
  public Object aroundCurrentLimiter(ProceedingJoinPoint joinPoint, AopInvalidAnno aopInvalidAnno) throws Throwable {
    log.info(joinPoint.getSignature().toLongString() + System.currentTimeMillis());
    Object rtn = joinPoint.proceed();
    log.info(joinPoint.getSignature().toLongString() + System.currentTimeMillis());
    return rtn;
  }
}

使用注解

@Component
public class AopInvalidComponent {

  @AopInvalidAnno
  public void aopValid() {
    System.out.println(this.getClass().getName());
  }

  public void aopInvalid() {
    aopValid();
  }
}

方法调用

public class AopInvalidComponentTest extends SKUnit {

  @Autowired
  private AopInvalidComponent aopInvalidComponent;

  @Test
  public void aopValid() {
    aopInvalidComponent.aopValid();// 2 line log and  1 line system out
  }

  @Test
  public void aopInvalid() {
    aopInvalidComponent.aopInvalid();// just 1 line system out
  }
}

结果

结果如测试案例注释,aopInvalid()方法调用时,并未打印审计日志。

原因

类内调用。当在被代理对象的方法中调用被代理对象的其他方法时,其实是没有用代理调用,是用了被代理对象本身调用的。

解决

配置:暴露代理对象

@Configuration
@EnableAspectJAutoProxy(exposeProxy = true)
@SpringBootApplication
public class DemoApplication {

  public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
  }

}

调用

@Component
public class AopInvalidComponent {

  @AopInvalidAnno
  public void aopValid() {
    System.out.println(this.getClass().getName());
  }

  public void aopInvalid() {
    aopValid();
  }

  public void aopProxy() {
    ((AopInvalidComponent) AopContext.currentProxy()).aopValid();
  }
}

验证

public class AopInvalidComponentTest extends SKUnit {

  @Autowired
  private AopInvalidComponent aopInvalidComponent;

  @Test
  public void aopValid() {
    aopInvalidComponent.aopValid();// 2 line log and  1 line system out
  }

  @Test
  public void aopInvalid() {
    aopInvalidComponent.aopInvalid();// just 1 line system out
  }

  @Test
  public void aopProxy() {
    aopInvalidComponent.aopProxy();// 2 line log and  1 line system out
  }
}

源码

https://github.com/ShaneKingBlog/org.shaneking.demo.aop.ivd

Search

    Donate

    ShaneKing

    Table of Contents