MicronautのAOPでログを自動出力する方法!初心者でも理解できる横断的関心事の基本
生徒
「Micronautで毎回メソッドの開始と終了にログを書くのが大変です……」
先生
「同じようなログ処理を何度も書いているなら、AOPを使うと自動化できます」
生徒
「AOPって難しそうなイメージがあります」
先生
「MicronautのAOPはアノテーション中心なので、仕組みを押さえればシンプルです」
生徒
「ログを自動で出すところから学びたいです」
先生
「では、AOPの考え方とログ出力の実装を順番に見ていきましょう」
1. MicronautにおけるAOPの役割
MicronautのAOPは、ログ出力やトランザクション管理、セキュリティチェックなど、 業務ロジックとは直接関係しない共通処理を分離するための仕組みです。 これらは横断的関心事と呼ばれ、通常のメソッド内に書くとコードが読みにくくなります。
AOPを使うことで、対象となるメソッドの前後に自動で処理を挿入できます。 Micronautではコンパイル時にAOPが適用されるため、実行時のオーバーヘッドが少なく、 高速に動作する点も特徴です。
2. ログ出力をAOPで行うメリット
ログをAOPで出力する最大のメリットは、コードの重複を防げる点です。 各サービスやコントローラに同じログ処理を書く必要がなくなり、 修正や仕様変更にも強くなります。
また、ログの形式や出力タイミングを一元管理できるため、 チーム開発でもログのばらつきを防ぐことができます。 初心者のうちは、この「共通化できる処理」を見つける感覚を身につけることが重要です。
3. ログ用の独自アノテーションを作成する
MicronautのAOPでは、まず独自アノテーションを作成し、 それを目印にして処理を差し込みます。 ここでは、ログを自動出力するためのアノテーションを定義します。
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface LogExecution {
}
このアノテーションを付けたクラスやメソッドが、 AOPによるログ出力の対象になります。
4. インターセプタでログ処理を実装する
次に、実際にログを出力するインターセプタを作成します。 インターセプタは、メソッドの呼び出し前後に処理を挟む役割を持ちます。
import io.micronaut.aop.MethodInterceptor;
import io.micronaut.aop.MethodInvocationContext;
import jakarta.inject.Singleton;
@Singleton
public class LogExecutionInterceptor 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;
}
}
interceptメソッド内で、context.proceedを呼び出すことで、 本来のメソッド処理が実行されます。 その前後にログを書くだけで、共通ログ処理が完成します。
5. アノテーションとインターセプタを結び付ける
作成したアノテーションとインターセプタを関連付けることで、 Micronautはどの処理にAOPを適用するか判断します。 ここではAroundアノテーションを使います。
import io.micronaut.aop.Around;
import io.micronaut.context.annotation.Type;
@Around
@Type(LogExecutionInterceptor.class)
public @interface LogExecution {
}
この設定により、LogExecutionが付与されたメソッドに対して、 LogExecutionInterceptorが自動的に適用されます。
6. サービスクラスでAOPログを利用する
最後に、実際のサービスクラスでアノテーションを使ってみます。 ここでは、単純な処理を行うサービスを例にします。
import jakarta.inject.Singleton;
@Singleton
public class SampleService {
@LogExecution
public void executeTask() {
System.out.println("業務処理を実行中");
}
}
このようにアノテーションを付けるだけで、 メソッドの開始と終了にログが自動出力されます。 ログ処理を一切書いていない点が、AOPの大きな利点です。
7. 初心者がつまずきやすいポイント
初心者がつまずきやすいのは、AOPが魔法のように見えてしまう点です。 実際には、アノテーションを目印にして、 インターセプタが呼び出されているだけです。
まずはログ出力のような単純な用途で使い、 仕組みを理解してから徐々に応用していくと、 MicronautのAOPが自然に使いこなせるようになります。