アスペクト指向プログラミング (Aspect-Oriented Programming)

アスペクト指向プログラミング(AOP)とは

複数のクラスにまたがる共通処理を、本来の業務処理から切り離して管理する設計手法です。

たとえば、次の処理は多くのクラスやメソッドで必要になります。

  • ログ出力
  • 認証・権限チェック
  • トランザクション管理
  • 実行時間の計測
  • 例外処理
  • キャッシュ
  • これらはアプリケーションの主要な目的ではありませんが、さまざまな場所に繰り返し登場します。このような処理を横断的関心事(Cross-cutting Concern)と呼びます。

    AOPを使わない場合

    public void createUser() {
        System.out.println("処理開始");
        long start = System.currentTimeMillis();
    
        // ユーザー登録処理
    
        System.out.println("実行時間: "
            + (System.currentTimeMillis() - start));
    }

    同じ計測処理を別のメソッドにも書くと、コードが重複します。

    AOPを使う場合

    業務処理は、その目的だけに集中できます。

    public void createUser() {
        // ユーザー登録処理
    }

    ログ出力や実行時間の計測は、別のクラスにまとめます。

    @Aspect
    @Component
    public class LoggingAspect {
    
        @Around("execution(* com.example.service.*.*(..))")
        public Object measure(ProceedingJoinPoint joinPoint) throws Throwable {
            long start = System.currentTimeMillis();
    
            try {
                return joinPoint.proceed();
            } finally {
                long elapsed = System.currentTimeMillis() - start;
                System.out.println("実行時間: " + elapsed + "ms");
            }
        }
    }

    主な用語

    用語意味
    Aspect切り離した共通処理をまとめたもの
    Join Point共通処理を差し込める地点。主にメソッドの実行時など
    Pointcut共通処理を適用する対象を指定する条件
    Advice実際に実行される共通処理
    Weaving対象の処理へAspectを組み込むこと

    Adviceの種類

  • Before:対象メソッドの実行前
  • After:対象メソッドの実行後
  • After Returning:正常終了後
  • After Throwing:例外発生後
  • Around:実行前後の両方を制御
  • Springで身近なAOP

    Springの次の機能もAOPによって実現されています。

    @Transactional
    public void updateAccount() {
        // データ更新
    }

    @Transactionalを付けると、Springがメソッドの前後にトランザクションの開始・コミット・ロールバック処理を追加します。

    メリット

  • 共通処理の重複を減らせる
  • 業務ロジックが読みやすくなる
  • 共通処理を一括して変更できる
  • ログやセキュリティの適用漏れを防ぎやすい
  • 注意点

  • コードを読んだだけでは、裏側で何が実行されるか分かりにくい
  • Pointcutの指定範囲を誤ると、意図しない処理にも適用される
  • AOPを多用すると、処理の流れやデバッグが複雑になる
  • 業務ロジックそのものをAspectへ移すのは避けた方がよい
  • [object Object]
    [object Object]