MicronautのAOPとDIの連携方法!InterceptorでBeanを活用する
生徒
「MicronautでAOPのInterceptorの中から他のBeanを使うことってできますか?」
先生
「はい、MicronautのDIとAOPは連携しているので、InterceptorでもBeanを注入して活用できます。」
生徒
「具体的にはどのように書けばいいんですか?」
先生
「それでは、InterceptorでBeanを利用する基本的な方法をステップごとに見ていきましょう!」
1. Interceptorとは何か?
MicronautのInterceptorは、メソッドの呼び出し前後に処理を挟むことができる仕組みです。AOP(Aspect Oriented Programming)を用いることで、ロギングやトランザクション、セキュリティチェックなど、共通処理を簡単に実装できます。InterceptorはDIと組み合わせることで、他のBeanの機能も呼び出せます。
2. DIとの連携の基本
Micronautでは@Singletonや@Injectを使ってBeanを定義・注入できます。Interceptorクラスも通常のBeanと同じように他のBeanを@Injectで注入可能です。これにより、Interceptor内でサービスやリポジトリのメソッドを呼び出せます。
import jakarta.inject.Singleton;
@Singleton
public class LoggingService {
public void log(String message) {
System.out.println("ログ: " + message);
}
}
3. Interceptorの作成方法
InterceptorはMethodInterceptorインターフェースを実装して作成します。呼び出したいBeanをコンストラクタに@Injectすると、DIで自動的に注入されます。
import io.micronaut.aop.MethodInterceptor;
import io.micronaut.aop.MethodInvocationContext;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
@Singleton
public class LoggingInterceptor implements MethodInterceptor<Object, Object> {
private final LoggingService loggingService;
@Inject
public LoggingInterceptor(LoggingService loggingService) {
this.loggingService = loggingService;
}
@Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
loggingService.log("メソッド呼び出し前: " + context.getMethodName());
Object result = context.proceed();
loggingService.log("メソッド呼び出し後: " + context.getMethodName());
return result;
}
}
4. Interceptorをメソッドに適用する
作成したInterceptorを利用するには、対象のBeanやメソッドにカスタムアノテーションを付与します。アノテーションに@Aroundをつけることで、指定したInterceptorが適用されます。
import io.micronaut.aop.Around;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
@Around(LoggingInterceptor.class)
public @interface Logged {
}
5. DIとInterceptorの組み合わせ例
Interceptorを適用したメソッド内でもDIしたBeanを利用できます。これにより、ログや通知、監査などの共通処理を一箇所で管理しながら、他のBeanの機能も呼び出せます。
import jakarta.inject.Singleton;
@Singleton
public class UserService {
@Logged
public void createUser(String username) {
System.out.println(username + "を作成しました");
}
}
6. 複数のBeanをInterceptorで活用する
Interceptorでは1つのBeanだけでなく、複数のBeanを注入して複雑な処理を実装可能です。例えば、ログサービスと通知サービスを組み合わせて、メソッド呼び出し後に通知を送信することもできます。
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
@Singleton
public class NotificationInterceptor implements MethodInterceptor<Object, Object> {
private final LoggingService loggingService;
private final NotificationService notificationService;
@Inject
public NotificationInterceptor(LoggingService loggingService, NotificationService notificationService) {
this.loggingService = loggingService;
this.notificationService = notificationService;
}
@Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
loggingService.log("処理開始: " + context.getMethodName());
Object result = context.proceed();
notificationService.send("処理完了通知: " + context.getMethodName());
return result;
}
}
7. Interceptorのメリット
Interceptorを使うと、共通処理をメソッドから分離して管理できます。DIと組み合わせることで、ログ、バリデーション、セキュリティ、通知などの処理を簡単に再利用可能にでき、コードの保守性と可読性が大幅に向上します。