如何删除时间测量逻辑



我需要计算一些方法的执行时间。这些是类中的私有方法,因此 Spring AOP 不合适。现在代码如下所示。

public void method() {
StopWatch sw = new StopWatch();
sw.start();
innerMethod1();
sw.stop();
Monitoring.add("eventType1", sw.getLastTaskTimeMillis());
sw.start();
innerMethod2("abs");
sw.stop();
Monitoring.add("eventType2", sw.getLastTaskTimeMillis());
sw.start();
innerMethod3(5, 29);
sw.stop();
Monitoring.add("eventType3", sw.getLastTaskTimeMillis());
}

但是,带有时间度量的插入内容适合业务逻辑。有什么解决办法吗?然后,这些数据将被记录在数据库中,以供格拉法纳使用。 我正在寻找AspectJ,但是启动应用程序时无法传递密钥。

当在不支持

或不受现有 LoadTimeWeaver 实现支持的环境中需要类检测时,JDK 代理可能是唯一的解决方案。对于这种情况,Spring 提供了 InstrumentationLoadTimeWeaver,它需要一个特定于 Spring 的(但非常通用的(VM 代理 org.springframework.instrument-{version}.jar(以前称为 spring-agent.jar(。 要使用它,您必须通过提供以下 JVM 选项来使用 Spring 代理启动虚拟机: -javaagent:/path/to/org.springframework.instrument-{version}.jar

<小时 />

马克·布拉姆尼克 如果我理解正确,那么对于方法

private List<String> innerMethod3(int value, int count) {
//
}
private String innerMethod2(String event)  {
//
}

需要方法

public  <T, R, U> U timed(T value, R count, BiFunction<T, R, U> function) {
long start = System.currentTimeMillis();
U result = function.apply(value, count);
Monitoring.add("method", System.currentTimeMillis() - start);
return result;
}
public <T, R> R timed(T value, Function<T, R> function) {
long start = System.currentTimeMillis();
R result = function.apply(value);
Monitoring.add("method", System.currentTimeMillis() - start);
return result;
}

和调用方法:

List<String> timed = timed(5, 5, this::innerMethod3);
String string = timed("string", this::innerMethod2);

但是如果 method4 有 4 个参数,那么我需要一种新的测量时间和一个新的功能界面

你可以采取很多方法,但所有方法都归结为重构。

方法1:

class Timed {
public static  void timed(String name, Runnable codeBlock) {
long from = System.currentTimeMillis();
codeBlock.run();
long to = System.currentTimeMillis();
System.out.println("Monitored: " + name + " : " + (to - from) + " ms");
}
public static <T> T timed(String name, Supplier<T> codeBlock)  {
long from = System.currentTimeMillis();
T result = codeBlock.get();
long to = System.currentTimeMillis();
System.out.println("Monitored: " + name + " : " + (to - from) + " ms");
return result;
}
}

笔记:

  • 为了简单起见,我使用了 Runnable/供应商接口,您可能希望为此创建自己的功能接口。
  • 我使用了 System.out - 您将使用现有的Monitoring.add调用

上述代码可以像这样使用:

Timed.timed("sample.runnable", ()-> { // Timed. can be statically imported for even further brevity
// some code block here
});
// will measure
int result = Timed.timed("sample.callable", () -> 42);
// will measure and result will be 42

另一种方法。

将代码重构为公共方法,并与已支持注释的 Micrometer 集成(请参阅 @Timed(。

我不知道Monitoring是什么,但千分尺已经包含与 Prometheus 的集成(以及其他可以存储指标的类似产品,后来从 grafana 使用(+ 它将测量的数学模型保存在内存中,并且不会将每次测量的信息保存在内存中。在自定义实现中,维护它是一段复杂的代码。

更新 1

不,你弄错了,你不需要维护不同版本的timed- 你只需要我在解决方案中提供的两个版本。如果您在问题中提出,您甚至不需要timed的第二个版本。

您的代码将变为:

public void method() {

Timed.timed("eventType1", () -> {
innerMethod1();
});

Timed.timed("eventType2", () -> {    
innerMethod2("abs");
});

Timed.timed("eventType3", () -> {    
innerMethod3(5, 29);
});

}

对于实际从"定时"代码返回某些值的情况,需要第二个版本:

例: 假设您有返回 String 的innerMethod4,因此您将编写以下代码:

String result = Timed.timed("eventType3", () -> {    
return innerMethod4(5, 29);
});  

最新更新