为定时方法调用编写java注释

roo*_*esh 25 java annotations timing

我想写一个java注释,它是方法调用的时间.这样的事情:

@TimeIt
public int someMethod() { ... }
Run Code Online (Sandbox Code Playgroud)

并且当调用此方法时,它应该在控制台上输出此方法花了多长时间

我知道如何在python中做到这一点,这就是我想要它做的事情:

from time import time, sleep

def time_it(func):
    def wrapper(*args, **kwargs):
        start = time()
        func(*args, **kwargs)
        stop = time()
        print "The function", func.__name__, " took %.3f" % (stop - start)
    wrapper.__name__ = func.__name__
    return wrapper

@time_it
def print_something(*args, **kwargs):
    print "before sleeping"
    print args, kwargs
    sleep(3) # wait 3 seconds
    print "after sleeping"

print_something(1, 2, 3, a="what is this?")
Run Code Online (Sandbox Code Playgroud)

所以我的问题是?我在哪里找到一些类似这样的apt文档,我试过文档,没有运气.有人可以帮忙写这样的东西吗?

San*_*rma 10

AFAIK,Tomasz说得不能用注释做到这一点.我认为混淆源于这样一个事实,即Python装饰器和Java注释共享相同的语法,但在它们提供的行为方面完全不同!

注释是附加到类/方法/字段的元数据.这篇博文讲述了使用AOP的计时方法.虽然它使用Spring,但基本前提仍然相同.如果你喜欢使用AOP编译器,那么翻译代码应该不会太难.另一参考文献(弹簧特异性)这里.

编辑:如果您的目标是在不使用完整的分析器的情况下为应用程序提供整体方法时序,则可以使用hprof来收集总执行统计信息.


Tom*_*zak 7

简单地说:你不能!

注释不是与代码一起自动启动的代码片段,它们只是注释,可以由代码加载或运行代码的其他程序使用的信息片段.

你需要的是AOP:面向方面的编程.


hea*_*svk 5

截至2016年,有一个漂亮的方面注释库jcabi-aspects.

来自文档:

使用@Loggable注释注释您的方法,并且每次调用它们时,SLF4J日志记录工具都将收到一条消息,其中包含执行细节和总执行时间:

public class Resource {
  @Loggable(Loggable.DEBUG)
  public String load(URL url) {
    return url.openConnection().getContent();
  }
}
Run Code Online (Sandbox Code Playgroud)

这样的东西会出现在日志中:

[DEBUG] #load('http://www.google.com'): returned "<html ..." in 23ms
Run Code Online (Sandbox Code Playgroud)

在这里阅读有关@Loggable的更多信息.


Rom*_*ano 5

我好几次想知道同样的事情,最后写了以下开头:

注释:

package main;
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 Clocking {

}
Run Code Online (Sandbox Code Playgroud)

对象的接口:

package main;

public interface Examples {
    @Clocking
    void thisIsAMethod();

    void thisIsAnotherMethod(String something);

    @Clocking
    void thisIsALongRunningMethod();
}
Run Code Online (Sandbox Code Playgroud)

调用处理程序:

package main;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.time.Duration;
import java.time.Instant;

public class ExamplesInvocationHandler implements InvocationHandler {
    // ******************************
    // Fields
    // ******************************
    private Examples examples = new ExamplesImpl();

    // ******************************
    // Public methods
    // ******************************
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // If the annotation is not present, just redirect the method call to its origin...
        if(!method.isAnnotationPresent(Clocking.class)) {
            return method.invoke(examples, args);
        }

        // ... otherwise log the execution time of it.
        Instant start = Instant.now();
        Object returnObj = method.invoke(examples, args);
        Instant end = Instant.now();

        // TODO: This is for demonstration purpose only and should use the application's logging system.
        System.out.println("Method " + method.getName() + " executed in " + Duration.between(end, start) + ".");

        return returnObj;
    }

    // ******************************
    // Inner classes
    // ******************************
    private static class ExamplesImpl implements Examples {
        @Override
        public void thisIsAMethod() {
            System.out.println("thisIsAMethod called!");
        }

        @Override
        public void thisIsAnotherMethod(String something) {
            System.out.println("thisIsAnotherMethod called!");
        }

        @Override
        public void thisIsALongRunningMethod() {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("thisIsALongRunningMethod called!");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后一个入口点来测试这个:

package main;
import java.lang.reflect.Proxy;

public class Main {
    public static void main(String[] args) {
        Examples examples = (Examples) Proxy.newProxyInstance(Examples.class.getClassLoader(), new Class[]{Examples.class}, new ExamplesInvocationHandler());

        examples.thisIsAMethod();
        examples.thisIsAnotherMethod("");
        examples.thisIsALongRunningMethod();
    }
}
Run Code Online (Sandbox Code Playgroud)

这需要改进,因为它需要 Proxy 来实例化我们的对象,因此您不能真正将它用于“已编写的通用”代码。但它可能会让你得到更完整的东西。