如何在带注释的方法的每个方法调用上执行某些操作?

时间:2019-06-12 15:23:16

标签: java spring annotations aspectj

我想用Java编写一个批注,该批注在执行带批注的方法之前和之后执行某些操作,类似于在Spring中使用方面可以完成的操作。

我已经尝试过Spring方面,但是它仅适用于Bean(as this guy here mentioned),并且我希望独立于Spring框架。

一个将字符串写入控制台的简单类:

public class Main {
    public static void main(String[] args) {
        say("How are you?");
    }

    @Hello
    private static void say(String s) {
        System.out.println(s);
    }
}

关联的注释:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

我需要类似的东西(从Spring方面推导)

public Object process(ProceedingJoinPoint proceedingJoinPoint) {
    System.out.println("Hello");
    Object proceed = null;
    try {
        proceed = proceedingJoinPoint.proceed();
    } catch (Throwable throwable) {
        throwable.printStackTrace();
    }
    System.out.println("world!");
    return proceed;
}

我想要以下输出:

  

你好

     

你好吗?

     

世界!

编辑:

我创建了以下Aspect(无注释),但是它不起作用

@lombok.extern.java.Log
public aspect Log {
    pointcut methodExecuted():execution(* **(..));

    void around(): methodExecuted() {
        log.info("Hello");
        proceed();
        log.info("world!");
    }
}

我的错误在哪里?

1 个答案:

答案 0 :(得分:1)

假设您已成功使用AspectJ编译器编译了方面,那么它应该可以与您使用的代码一起使用,只是它将记录所有方法的执行,即main(..),因此您将在此之前将方面的输出设置为两次在“你好吗?”之后。如果看不到任何内容,则可能是在设置构建系统时出错了。

您应该更改切入点以实际将日志记录限制为带注释的方法:execution(* *(..)) && @annotation(Hello)。此外,如果您的周围建议具有空返回类型,则日志记录将不适用于非空方法。因此,您应该使用返回类型Object并实际上返回proceed()的结果。

我也强烈建议您不要盲目地使用像AspectJ这样的强大工具,还应该在使用前先学习一些文档。很明显,您还没有这样做或者只是很粗略地做到了。这样,您就可以成为拥有能力有限的工具的用户。;-)

这是我的MCVE

package de.scrum_master.app;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target(METHOD)
public @interface Hello {}
package de.scrum_master.app;

public class Application {
  public static void main(String[] args) {
    say("How are you?");
  }

  @Hello
  private static void say(String s) {
    System.out.println(s);
  }
}
package de.scrum_master.aspect;

import de.scrum_master.app.Hello;

public aspect LoggingAspect {
  pointcut methodExecuted() : execution(* *(..)) && @annotation(Hello);

  Object around(): methodExecuted() {
    System.out.println("Hello");
    Object result = proceed();
    System.out.println("world!");
    return result;
  }
}

控制台日志:

Hello
How are you?
world!