MicronautのMethodInterceptorの使い方!独自ロジックを挟む基本と応用
生徒
「MicronautのAOPで、MethodInterceptorというクラスをよく見かけますが、これは何をするものなんですか?」
先生
「MethodInterceptorは、メソッドの実行前後に独自の処理を挟むための仕組みです。MicronautのAOPを実現する中心的な存在ですね。」
生徒
「前後に処理を挟めるということは、ログやチェック処理も書けるんですか?」
先生
「その通りです。基本を押さえれば、いろいろな共通処理を安全に追加できます。順番に見ていきましょう。」
1. MethodInterceptorとは何か
MicronautのMethodInterceptorは、AOPの仕組みの中で実際に処理を行うためのインターフェースです。特定のメソッドが呼び出されるタイミングで、処理の前後に独自ロジックを追加できます。
初心者が最初に理解しておきたいポイントは、MethodInterceptor自体が業務ロジックを書く場所ではないという点です。あくまで、ログ出力や処理時間の計測など、複数のクラスで共通して使いたい処理をまとめるために利用します。
2. MicronautのAOPとMethodInterceptorの関係
Micronautでは、AOPという考え方の中でMethodInterceptorが使われます。AOPは全体の仕組みを指し、MethodInterceptorは実装の中心となる部品です。
アノテーションによって対象となるメソッドが指定され、そのアノテーションに対応するMethodInterceptorが呼び出されます。この流れを理解することで、MicronautのAOP構造が自然と見えてきます。
3. MethodInterceptorの基本的な動作の流れ
MethodInterceptorは、メソッド呼び出しを包み込むように動作します。まずメソッド実行前の処理が行われ、その後に本来のメソッドが実行され、最後にメソッド実行後の処理が行われます。
この一連の流れにより、元のコードを変更することなく、処理の振る舞いだけを追加できます。これがAOPとMethodInterceptorの大きなメリットです。
4. MethodInterceptor用アノテーションの作成例
まずは、MethodInterceptorを適用するためのアノテーションを作成します。ここでは、処理の前後でメッセージを表示するためのシンプルなアノテーションを用意します。
import io.micronaut.aop.Around;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Around
public @interface MethodLog {
}
このアノテーションは、どのメソッドにMethodInterceptorを適用するかを示すための目印になります。
5. MethodInterceptorの基本的な実装方法
次に、MethodInterceptorを実装したクラスを作成します。ここでは、メソッドの実行前後でログを出力する例を示します。
import io.micronaut.aop.InterceptorBean;
import io.micronaut.aop.MethodInterceptor;
import io.micronaut.aop.MethodInvocationContext;
import jakarta.inject.Singleton;
@Singleton
@InterceptorBean(MethodLog.class)
public class MethodLogInterceptor implements MethodInterceptor<Object, Object> {
@Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
System.out.println("メソッド開始: " + context.getMethodName());
Object result = context.proceed();
System.out.println("メソッド終了: " + context.getMethodName());
return result;
}
}
context.proceedを呼び出すことで、本来のメソッド処理が実行されます。この呼び出しを忘れると、元の処理が実行されない点に注意が必要です。
6. サービスクラスでMethodInterceptorを使う例
作成したMethodInterceptorを、実際のサービスクラスで使ってみます。業務ロジックはできるだけ単純にして、動きが分かりやすい例にしています。
import jakarta.inject.Singleton;
@Singleton
public class UserService {
@MethodLog
public String createUser(String name) {
return "ユーザー作成: " + name;
}
}
このメソッドが呼び出されると、メソッド開始と終了のログが自動的に出力されます。UserService自体は、本来の処理だけを書けばよくなります。
7. MethodInterceptorを使った処理時間計測の応用例
MethodInterceptorは、処理時間の計測にもよく使われます。開始時刻と終了時刻を取得し、その差を出力することで、簡単なパフォーマンス確認ができます。
@Singleton
@InterceptorBean(MethodLog.class)
public class TimeMeasureInterceptor 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("実行時間: " + (end - start) + "ms");
return result;
}
}
このように、同じ仕組みを使ってさまざまな独自ロジックを挟めるのがMethodInterceptorの魅力です。
8. 初心者がMethodInterceptorを使うときの考え方
MethodInterceptorは非常に便利ですが、何でもここに書くとコードの流れが分かりにくくなります。業務ロジックとは直接関係のない共通処理に限定して使うことが重要です。
最初はログ出力や簡単な計測処理など、動きが目で確認できる用途から始めると、MicronautのAOPとMethodInterceptorの理解が深まります。