当前位置: 首页 > 知识库问答 >
问题:

Micrometer TimedAspect不拦截对带有@Timed注释的方法的调用

伏建修
2023-03-14

我试图使用测微计来记录Java应用程序中的执行时间。这与我的另一个问题有关,即使用的@Timed注释。

我有一个类< code>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) {}
}

我定义了一个自定义注释< code>@Measured

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

和一个测量方面来拦截对用我的@测量注释的方法的调用:

@Aspect
public class MeasuredAspect {
    @Around("execution(* *(..)) && @annotation(Measured)")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        return AppMetrics.getInstance().handle(pjp);

    }
}

在我的 AppMetrics 类中,我初始化了千分尺的定时观察实例,并在句柄(进程连接点 pjp) 方法中将“进程连接点 pjp”传递给“时标”实例。

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);
    }
}

在我的应用程序main中,我创建了一个< code>CountedObject对象,并调用了< code>measuredFunction()和< code>timedFunction(),然后我检查了我的< code > registry . getmeters();只找到了由< code > Measured function()[同时由@Measured和@Timed注释]使用的定时器1,而不存在应由< code > Timed function()[仅由@Timed注释]使用的定时器2。

我使用eclipse和AspectJ开发工具插件,我的项目是一个具有AspectJ功能的Gradle项目。我在我的Gradle插件中使用< code > id " io . free fair . AspectJ " version " 5 . 1 . 1 " 插件。这是一个基本的java应用程序,而不是Spring应用程序。

需要完成哪些配置或需要更改哪些代码,以便千分尺TimedAspect可以直接拦截我的方法调用[即timedFunction()应该定时,并且timer2应该在注册表中找到]而不需要我的自定义注释?

共有2个答案

文嘉禧
2023-03-14

我不知道你对此有什么期望:

public Object handle(ProceedingJoinPoint pjp) throws Throwable {
    return timedAspect.timedMethod(pjp);
}

如果我理解正确的话,它没有任何作用。您可以遵循以下指南为项目正确设置AspectJ。完成后,TimedAspect应该可以工作,您不需要MeasuredAspect@Measured,只需设置AspectJ即可。

吴炎彬
2023-03-14

我为您创建了一个示例项目:

https://github.com/kriegaex/SO_AJ_MicrometerTimed_67803726

引用read-me(抱歉,但StackOverflow上不赞成仅包含链接的答案):

在https://github . com/micrometer-metrics/micrometer/issues/1149和StackOverflow上,关于Micrometer的< code>@Timed注释的一个常见问题是,为什么它可以与Spring AOP一起工作,但不能在编译时编织(CTW)的上下文中将Micrometer用作本机AspectJ的方面库,例如与AspectJ Maven插件一起工作。当提供一个指向< code>TimedAspect的< code>aop.xml时,它可以与加载时织入(LTW)一起工作,但是在CTW中,方面永远不会起作用。

原因是方面是用Javac编译的,而不是用AspectJ编译器(AJC ),这是“完成”Java类所必需的,也就是说,为了成为一个完整的AspectJ方面,要增强它的字节码。LTW代理在类加载期间动态地完成这项工作,但是在CTW上下文中,您需要明确地告诉AJC在Micrometer库上进行编译后编织(也称为二进制编织),产生新编织的类文件。这是通过在AJC的inpath上放置Micrometer来完成的,以确保其类文件被转换并写入目标目录。AspectJ Maven中的inpath是通过< code >配置的

> < li>

您可以在单独的Maven模块中创建自己的woven版本库,然后使用该模块代替Micrometer。在这种情况下,您需要在消费模块中排除原始的Micrometer库,以确保未编织的类文件不再位于类路径中,并且被意外使用。

在此示例项目中所示的方法是单模块方法,使用 Maven Shade 构建一个可执行的超级 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注释实际上导致Microeter的TimedAspect被编织到我们的应用程序代码中。以下是方面为示例应用程序创建的测量值:

method.timed
  {class=de.scrum_master.app.Application,exception=none,method=doSomething}
  throughput=0.166667/s mean=0.11842469s max=0.2146482s
 类似资料:
  • 我试图让aspectj拦截带注释的方法: 我删除了!为了简洁起见,在(InterceptMeAspect)内,但它并没有拦截太多。如果我删除注释约束(在(@InterceptMe*)内),它可以工作,但会拦截所有内容,这会造成一个大问题。 输出字节码似乎有完整的注释,所以我希望注释标准匹配。我正在或试图进行编译时编织。这很重要,因为我有另一个方面确实使用上面相同的方法工作。我怀疑该方面正在搞乱这个

  • 所以我有一个自定义注释 我想使用它将方面编织到方法中(AspectJ,<代码>@注释(截取) )。 其思想是,当我直接注释方法截取时,我将方面编织入其中——这一部分起作用——或者如果我注释类,则应将方面编织入其所有(公共)方法中——这一部分不起作用。 此外,如果我对一个类及其一个方法进行注释,则方面应该只被编织一次,方法级注释将覆盖类级注释。 本质上,我想要一个“如果有类级注释,但只有在还没有方法

  • 我正在编写一个库/sdk,它可以拦截任何使用自定义注释进行注释的方法。代码的工作方式有点像这样 截取这个的方面有一个切入点表达式 当我在与相同的包中描述方面时,此代码工作正常。但是,如果我创建一个单独的库并定义方面,因为它无法拦截。有帮助吗? 回应@Bond的评论 Spring版本:Spring上下文-4.1.7。发布aspectj-1.6.5问题的关键是注释不会在同一个项目中使用。在编译之后,它

  • 问题内容: 我有这个代码 有什么方法可以在没有子类化或修改类且没有工厂的情况下拦截呼叫? 编辑:抱歉忘了提到这是在Android平台上。 问题答案: 您是否考虑过面向方面的编程,甚至还考虑过AspectJ?有关AspectJ / Android的信息,请参见此处和此处。

  • 问题内容: 我正在用python实现RESTful Web服务,并想通过拦截函数调用并记录其执行时间等方式来添加一些QOS记录功能。 基本上,我想到了所有其他服务都可以从中继承的类,该类会自动覆盖默认方法的实现,并将其包装在logger函数中。实现此目标的最佳方法是什么? 问题答案: 像这样吗 这暗示着在您的方法中添加装饰器(如果您愿意,也可以基于此创建一个显式装饰器): 当您现在尝试类似的方法:

  • 我试图截取带注释方法的执行,以记录执行时间;因此,我创建了一个新注释: 我将注释应用于我想要跟踪的方法(该方法的类没有注释,如@Service或@Component;这是一个问题吗?) 然后我创建类和@周围方法: 我在pom中添加了spring boot starter aop依赖项,并在主类中添加了@EnableSpectProxy(带@SpringBootApplication注释的类)。我希