MicronautのAOPでメソッドの実行時間を計測する方法
生徒
「Micronautでメソッドがどれくらい時間がかかっているかを測りたいです。簡単にできますか?」
先生
「はい、MicronautのAOP機能を使うと、既存のコードをほとんど修正せずにメソッドの実行時間を計測できます。」
生徒
「AOPって、どういう仕組みで時間を測るんですか?」
先生
「AOPはメソッドの前後に処理を挿入できる仕組みです。ここでは、メソッド実行前に開始時刻を記録し、実行後に終了時刻を取得して差分を計算します。」
1. AOPでメソッド時間計測の基本
MicronautではAOPを使って、メソッドの前後に独自の処理を挟むことができます。実行時間の計測も同様に、メソッド実行の前後で時刻を取得して差分を出すだけなので非常に簡単です。これにより、ログに実行時間を出力したり、パフォーマンス分析が行えます。
2. 実際にアノテーションを作る
まず、実行時間計測用のアノテーションを作成します。簡単な設定だけでメソッドに付与できるようにします。
import io.micronaut.aop.Around;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Around
public @interface Timed {
}
3. インターセプタの作成
次に、@Timedアノテーションが付いたメソッドの前後に処理を挟むInterceptorを作ります。
import io.micronaut.aop.MethodInterceptor;
import io.micronaut.aop.MethodInvocationContext;
import jakarta.inject.Singleton;
@Singleton
public class TimedInterceptor implements MethodInterceptor<Object, Object> {
@Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
long start = System.currentTimeMillis();
Object result = context.proceed();
long end = System.currentTimeMillis();
System.out.println(context.getMethodName() + "の実行時間: " + (end - start) + "ms");
return result;
}
}
4. サービスにアノテーションを付与
Interceptorが用意できたら、測定したいメソッドに@Timedを付与します。
import jakarta.inject.Singleton;
@Singleton
public class CalculationService {
@Timed
public int heavyComputation() throws InterruptedException {
Thread.sleep(500);
return 42;
}
}
この設定により、heavyComputationメソッドが呼ばれるたびに、実行時間がログに出力されます。
5. 複数メソッドへの適用
同じInterceptorは他のメソッドにも適用可能です。@Timedを付けるだけで、共通処理として実行時間計測が行われるため、コードの重複を避けられます。
@Singleton
public class UserService {
@Timed
public void createUser() {
// ユーザー作成処理
}
@Timed
public void deleteUser() {
// ユーザー削除処理
}
}
6. ログ出力の応用
System.out.println以外にも、MicronautのLoggingフレームワークを使えば、ログレベルに応じた記録が可能です。これにより、開発環境や本番環境で適切なログ管理ができます。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class TimedInterceptor implements MethodInterceptor<Object, Object> {
private static final Logger LOG = LoggerFactory.getLogger(TimedInterceptor.class);
@Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
long start = System.currentTimeMillis();
Object result = context.proceed();
long end = System.currentTimeMillis();
LOG.info("{}の実行時間: {}ms", context.getMethodName(), (end - start));
return result;
}
}
7. 実運用での注意点
メソッド実行時間を頻繁に計測すると、ログが大量になったりパフォーマンスに影響が出る場合があります。重要な処理やボトルネックになりやすい部分だけに限定するなど、運用上の工夫が必要です。
8. まとめ以外の活用例
このAOPによる計測方法は、メトリクス収集や監視ツールへの連携にも応用可能です。例えばPrometheusやGrafanaに送る前処理として利用することで、サービス全体のパフォーマンス分析に活かせます。