如何在注释方法的每个方法调用上执行某些操作?
How do I perform something on each method call of an annotated method?
我想在 Java 中写一个注解,它在执行注解的方法之前和之后执行一些事情,类似于 Spring 中可以用 aspects 完成的事情。
我已经尝试了 Spring 方面,但它只适用于 Beans (as this guy here mentioned),我想保持独立于 Spring 框架。
将字符串写入控制台的简单 class:
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;
}
我想要以下输出:
Hello
How are you?
world!
编辑:
我创建了以下方面(没有注释),但它不起作用
@lombok.extern.java.Log
public aspect Log {
pointcut methodExecuted():execution(* **(..));
void around(): methodExecuted() {
log.info("Hello");
proceed();
log.info("world!");
}
}
我的错误在哪里?
假设您使用 AspectJ 编译器成功编译了方面,它应该可以与您使用的代码一起工作,只是它会记录所有方法执行,即 main(..)
,所以您会看到方面的输出"How are you?"前后两次。如果您没有看到任何内容,则可能是您在设置构建系统时犯了错误。
您应该更改切入点以实际将日志记录限制为带注释的方法:execution(* *(..)) && @annotation(Hello)
。此外,如果您的 around 通知具有 void return 类型,则日志记录将无法使用 non-void 方法。所以你应该使用 return 类型的 Object
而实际上 return proceed()
.
的结果
我还强烈建议您不要盲目使用像 AspectJ 这样强大的工具,而是在使用之前先研究一些文档。很明显,您没有这样做或只是非常粗略地这样做。然后就得到了用工具当not-so-capable-user的效果 ;-)
这是我的 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!
我想在 Java 中写一个注解,它在执行注解的方法之前和之后执行一些事情,类似于 Spring 中可以用 aspects 完成的事情。
我已经尝试了 Spring 方面,但它只适用于 Beans (as this guy here mentioned),我想保持独立于 Spring 框架。
将字符串写入控制台的简单 class:
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;
}
我想要以下输出:
Hello
How are you?
world!
编辑:
我创建了以下方面(没有注释),但它不起作用
@lombok.extern.java.Log
public aspect Log {
pointcut methodExecuted():execution(* **(..));
void around(): methodExecuted() {
log.info("Hello");
proceed();
log.info("world!");
}
}
我的错误在哪里?
假设您使用 AspectJ 编译器成功编译了方面,它应该可以与您使用的代码一起工作,只是它会记录所有方法执行,即 main(..)
,所以您会看到方面的输出"How are you?"前后两次。如果您没有看到任何内容,则可能是您在设置构建系统时犯了错误。
您应该更改切入点以实际将日志记录限制为带注释的方法:execution(* *(..)) && @annotation(Hello)
。此外,如果您的 around 通知具有 void return 类型,则日志记录将无法使用 non-void 方法。所以你应该使用 return 类型的 Object
而实际上 return proceed()
.
我还强烈建议您不要盲目使用像 AspectJ 这样强大的工具,而是在使用之前先研究一些文档。很明显,您没有这样做或只是非常粗略地这样做。然后就得到了用工具当not-so-capable-user的效果 ;-)
这是我的 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!