如何删除时间测量逻辑

How to remove the time measurement logic

我需要计算一些方法的执行时间。这些是 class 中的私有方法,因此 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());
   }

但是带有时间度量的插入符合业务逻辑。有什么解决办法吗?然后这些数据会记录到grafana的数据库中。我正在寻找 AspectJ,但在启动应用程序时无法传递密钥。

When class instrumentation is required in environments that do not support or are not supported by the existing LoadTimeWeaver implementations, a JDK agent can be the only solution. For such cases, Spring provides InstrumentationLoadTimeWeaver, which requires a Spring-specific (but very general) VM agent,org.springframework.instrument-{version}.jar (previously named spring-agent.jar). To use it, you must start the virtual machine with the Spring agent, by supplying the following JVM options: -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个参数,那么我需要一个新的时间测量方法和一个新的功能接口

您可以采用多种方法,但所有方法都归结为重构。

方法一:

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 / Supplier 接口,您可能想为此创建自己的功能接口。
  • 我已经使用了 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

另一种方法。

将代码重构为 public 方法并与 Micrometer that already has annotations support (see @Timed) 集成。

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

更新 1

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

的第二个版本

您的代码将变为:

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

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

第二个版本对于您实际 return 来自“定时”代码的一些值的情况是必需的:

示例: 假设您有 innerMethod4 和 returns 字符串,因此您将编写以下代码:

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