java - Micrometer TimedAspect 不会拦截对使用 @Timed 注释的方法的调用
问题描述
我正在尝试使用Micrometer在我的 Java 应用程序中记录执行时间。这与我关于使用注释的其他问题有关。@Timed
我有一个CountedObject
具有以下两种方法的类:
@Measured
@Timed(value = "timer1")
public void measuredFunction() {
try {
int sleepTime = new Random().nextInt(3) + 1;
Thread.sleep(sleepTime * 1000L);
} catch (InterruptedException e) {}
}
@Timed(value = "timer2")
public void timedFunction() {
try {
int sleepTime = new Random().nextInt(3) + 1;
Thread.sleep(sleepTime * 1000L);
} catch (InterruptedException e) {}
}
我已经定义了一个自定义注释@Measured
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Measured {
}
并MeasuredAspect
拦截对使用我的注释进行注释的方法的调用@Measured
:
@Aspect
public class MeasuredAspect {
@Around("execution(* *(..)) && @annotation(Measured)")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
return AppMetrics.getInstance().handle(pjp);
}
}
在我的AppMetrics
课程中,我初始化了千分尺的TimedAspect实例,并在handle(ProceedingJoinPoint pjp)
方法中将其传递ProceedingJoinPoint pjp
给 TimedAspect 实例。
public class AppMetrics {
private static final AppMetrics instance = new AppMetrics();
private MeterRegistry registry;
private TimedAspect timedAspect;
public static AppMetrics getInstance() {
return instance;
}
private AppMetrics() {
this.registry = new SimpleMeterRegistry();
this.timedAspect = new TimedAspect(registry);
}
public Object handle(ProceedingJoinPoint pjp) throws Throwable {
return timedAspect.timedMethod(pjp);
}
}
在我的应用程序主应用程序中,我创建了一个对象CountedObject
并调用measuredFunction()
,timedFunction()
然后我检查了[由@Measured 和 @Timed 注释的] 使用的registry.getMeters();
唯一timer1 ,而应该由[仅由@注释的timer2定时] 不存在。measuredFunction()
timedFunction()
我正在使用带有AspectJ 开发工具插件的 eclipse,我的项目是一个具有 AspectJ 功能的 Gradle 项目。我id "io.freefair.aspectj" version "5.1.1"
在我的 Gradle 插件中使用插件。这是一个基本的 Java 应用程序,而不是 Spring 应用程序。
需要进行哪些配置或更改哪些代码,以便千分尺TimedAspect可以直接拦截我的方法调用[即timedFunction()
应该定时并且应该在注册表中找到timer2 ],而无需我的自定义注释?
解决方案
我为您创建了一个示例项目:
https://github.com/kriegaex/SO_AJ_MicrometerTimed_67803726
引用自述文件(抱歉,StackOverflow 不赞成只包含链接的答案):
在https://github.com/micrometer-metrics/micrometer/issues/1149和 StackOverflow 上,关于 Micrometer@Timed
注释的常见问题解答是,为什么它与 Spring AOP 一起使用,但在使用 Micrometer 作为本机 AspectJ 的方面库时却不行编译时编织 (CTW) 的上下文,例如使用 AspectJ Maven 插件。aop.xml
当提供指向时,它可以与加载时编织 (LTW)一起使用TimedAspect
,但在 CTW 中,方面永远不会起作用。
原因是方面是用 Javac 编译的,而不是用 AspectJ 编译器 (AJC) 编译的,这是“完成”Java 类所必需的,即增强其字节码以成为完整的 AspectJ 方面。LTW 代理在类加载期间动态执行此操作,但在 CTW 上下文中,您需要明确告诉 AJC 在 Micrometer 库上进行编译后编织(也称为二进制编织),生成新编织的类文件。这是通过将 Micrometer 放在 AJC 的输入路径上来完成的,以确保其类文件正在被转换并写入目标目录。AspectJ Maven 中的 inpath 是通过<weaveDependencies>
. 至少有两种方法可以做到这一点:
您可以在单独的 Maven 模块中创建自己的库的编织版本,然后使用该模块而不是 Micrometer。在这种情况下,您需要在消费模块中排除原始的 Micrometer 库,以确保未编织的类文件不再位于类路径中并被意外使用。
此示例项目中显示的方式是单模块方法,使用 Maven Shade 构建可执行的 uber JAR。Micrometer 类文件不像第一种方法那样是可重用的库,但它非常适合演示目的,因为我们可以只运行示例应用程序并检查其输出:
$ mvn clean package
...
[INFO] --- aspectj-maven-plugin:1.12.6:compile (default) @ SO_AJ_MicrometerTimed_67803726 ---
[INFO] Showing AJC message detail for messages of types: [error, warning, fail]
[INFO] Join point 'method-execution(void de.scrum_master.app.Application.doSomething())' in Type 'de.scrum_master.app.Application' (Application.java:23) advised by around advice from 'io.micrometer.core.aop.TimedAspect' (micrometer-core-1.7.0.jar!TimedAspect.class(from TimedAspect.java))
...
[INFO] --- maven-shade-plugin:3.2.4:shade (default) @ SO_AJ_MicrometerTimed_67803726 ---
[INFO] Including org.hdrhistogram:HdrHistogram:jar:2.1.12 in the shaded jar.
[INFO] Including org.latencyutils:LatencyUtils:jar:2.0.3 in the shaded jar.
[INFO] Including org.aspectj:aspectjrt:jar:1.9.6 in the shaded jar.
[INFO] Excluding io.micrometer:micrometer-core:jar:1.7.0 from the shaded jar.
[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing C:\Users\me\java-src\SO_AJ_MicrometerTimed_67803726\target\SO_AJ_MicrometerTimed_67803726-1.0-SNAPSHOT.jar with C:\Users\me\java-src\SO_AJ_MicrometerTimed_67803726\target\SO_AJ_MicrometerTimed_67803726-1.0-SNAPSHOT-shaded.jar
[INFO] Dependency-reduced POM written at: C:\Users\me\java-src\SO_AJ_MicrometerTimed_67803726\target\dependency-reduced-pom.xml
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
$ java -jar target/SO_AJ_MicrometerTimed_67803726-1.0-SNAPSHOT.jar
Juni 05, 2021 1:12:27 PM io.micrometer.core.instrument.push.PushMeterRegistry start
INFO: publishing metrics for LoggingMeterRegistry every 1m
Juni 05, 2021 1:13:00 PM io.micrometer.core.instrument.logging.LoggingMeterRegistry lambda$publish$5
INFO: method.timed{class=de.scrum_master.app.Application,exception=none,method=doSomething} throughput=0.166667/s mean=0.11842469s max=0.2146482s
请特别注意这些日志行(插入换行符以提高可读性):
Join point 'method-execution(void de.scrum_master.app.Application.doSomething())'
in Type 'de.scrum_master.app.Application' (Application.java:23)
advised by around advice from 'io.micrometer.core.aop.TimedAspect'
(micrometer-core-1.7.0.jar!TimedAspect.class(from TimedAspect.java))
以上证明@Timed
注释实际上导致 MicrometerTimedAspect
被编织到我们的应用程序代码中。以下是方面为示例应用程序创建的测量值:
method.timed
{class=de.scrum_master.app.Application,exception=none,method=doSomething}
throughput=0.166667/s mean=0.11842469s max=0.2146482s
推荐阅读
- javascript - 如何让我的关闭按钮在不同尺寸的屏幕上工作?
- html - 如何确保边框半径应用于图像而不是其容器?
- python - Python:重新排列方程以采用特定形式
- c# - 如何获取鼠标相对于世界的坐标?
- python - TypeError:“RelatedManager”对象不可迭代 - serializers.ListField()
- xamarin.forms - 在 Xamarin.forms 中从 Json 写入文本文件(或 PDF 文件)
- arrays - 如何在swift中过滤对象的3维数组
- python - 将文件从客户端上传到服务器时出现问题
- python - 如何更改 QCombobox 下拉项背景颜色的颜色
- javascript - Puppeteer page.mouse.down() / up() 和点击物理鼠标不一样?