メソッド呼び出しの時間を回すJavaアノテーションを書きたい。次のようなもの:
@TimeIt
public int someMethod() { ... }
このメソッドが呼び出されると、このメソッドにかかった時間をコンソールに出力する必要があります
私はそれを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?")
だから私の質問は?このようなものを書くためのドキュメントはどこにありますか? apt
ドキュメントを試しましたが、うまくいきませんでした。誰かがこのようなものを書くのを手伝ってくれる?
AFAIK、Tomaszは、これは注釈を使用して行うことはできないと言っています。混乱は、PythonデコレータとJavaアノテーションは同じ構文を共有しますが、提供する動作の点で完全に異なるという事実から生じていると思います!
アノテーションは、クラス/メソッド/フィールドに添付されたメタデータです。 このブログ投稿 は、AOPを使用したタイミング手法のポイントに対処します。 Springを使用していますが、基本的な前提は同じです。 AOPコンパイラを使用するのが良ければ、コードを変換することはそれほど難しくありません。別の参照(春固有) ここ 。
[〜#〜] edit [〜#〜]:本格的なプロファイラーを使用せずに、アプリケーションの全体的なメソッドタイミングを設定することが目的の場合は、 hprof を使用して、合計実行統計を収集できます。
簡単に言えば、できません!
アノテーションは、コードと一緒に自動的に開始されるコードではなく、単なるアノテーションであり、コードの読み込みや実行など、コードを操作する他のプログラムが使用できる情報です。
必要なのはAOP:アスペクト指向プログラミングです。
2016年の時点で、気の利いたアスペクトアノテーションライブラリがあります jcabi-aspects 。
ドキュメントから:
メソッドに@Loggableアノテーションを付けると、メソッドが呼び出されるたびに、SLF4Jロギング機能が実行の詳細と合計実行時間を含むメッセージを受け取ります。
public class Resource {
@Loggable(Loggable.DEBUG)
public String load(URL url) {
return url.openConnection().getContent();
}
}
次のようなものがログに表示されます。
[DEBUG] #load('http://www.google.com'): returned "<html ..." in 23ms
@Loggableの詳細を読む ここ 。
Coda Hale Metrics ライブラリを確認してください。この機能を提供するメソッドに@Timedアノテーションを提供します。あなたがそれをしている間にチェックしてください Code Hale Dropwizard それが彼らのサービスフレームワークにどのように統合されたかの例があります。
@GET
@Timed
public Saying sayHello(@QueryParam("name") Optional<String> name) {
return new Saying(counter.incrementAndGet(),
String.format(template, name.or(defaultName)));
}
すべての否定者にもかかわらず、あなたはこれを行うことができます。 Javaアノテーションは、操作するソースファイルまたはクラスファイルを変更できないため、オプションは次のとおりです。
1)スーパークラスを使用します。注釈プロセッサは、抽象メソッドを実行するスーパークラスを生成できます。実際のクラスはこのメソッドを実装します。欠点は、スーパークラスが実装を提供できるように、時間を計りたいメソッドの名前を変更する必要があることです。結果は次のようになります
@BenchmarkMe( extend="MySuperClass" )
public class MyClass extends BenchmarkMyClass {
public void normalMethod() { ... }
public void bench_myMethod() { ... }
}
と注釈プロセスは生成されます:
public class BenchmarkMyClass extends MySuperClass {
public abstract void bench_myMethod();
public void myMethod() {
benchmarkStart();
try {
bench_myMethod();
} finally { benchmarkStop(); }
}
}
命名規則を使用して、私の例では「bench_」という接頭辞が使用されたため、どのメソッドにタイミングをとるべきかを示します。
2)ClassFileTranformerとアノテーションを使用するアプローチは、タイミングに関心のあるメソッドをマークするために使用できるランタイムアノテーションを作成することです。実行時に、ClassFileTransformerがコマンドラインで指定され、バイトコードを変換してタイミングコードを挿入します。
バイトコードの操作が好きでない限り、AOPを使用する方が適切ですが、[〜#〜] is [〜#〜]が可能です。
Java.lang.reflect.Proxyを誰も指摘していないことに驚いています。古いスレッドですが、この情報は誰かに役立つと思います。
プロキシは与える興味深いプロパティを持っています
オブジェクトに何らかのインターフェースを実装させることで、すべてのオブジェクトにこのプロキシを設定するか、Comparableを使用できます。
動的プロキシのセクションをデコレータとして探します。
同じことを何度か思いつき、次のように書き始めました。
注釈:
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 {
}
オブジェクトのインターフェース:
package main;
public interface Examples {
@Clocking
void thisIsAMethod();
void thisIsAnotherMethod(String something);
@Clocking
void thisIsALongRunningMethod();
}
呼び出しハンドラ:
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!");
}
}
}
最後にこれをテストするためのエントリポイント:
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();
}
}
オブジェクトをインスタンス化するためにプロキシが必要であり、「一般的な既に記述された」コードには実際には使用できないため、これには改善が必要です。しかし、それはあなたをより完全な何かに導くかもしれません。
Javaではそれほど簡単ではありません。基本的なアイデアはこれです:
この記事はあなたを始めるでしょう: http://today.Java.net/pub/a/today/2008/04/24/add-logging-at-class-load-time-with-instrumentation.html 。
BTraceを使用してこれをさらに簡単にすることもできます。 http://kenai.com/projects/btrace/pages/Home
すでに述べたように、AOPまたはhprofはほとんどのニーズをカバーできませんが、主張する場合はJSR269を使用した回避策があります。参考までに、aptは廃止され、注釈処理APIとツールが1.6に組み込まれました(そして、それは刺激的な名前JSR269で呼び出されます)。
回避策は、_@TimeIt
_アノテーションを持つメソッドを含むクラスを拡張するクラスを生成するアノテーションプロセッサを作成することです。この生成されたクラスは、timedメソッドをオーバーライドする必要があります。Python _time_it
_のようになりますが、func(*args, **kwargs)
という行はsuper.methodName(arg1, arg2, ...)
。
ただし、2つの注意点があります。