AOPの基礎 動的プロキシを触る

動的プロキシクラスを使用することによって、実行時にインターフェイスを介して実行対象メソッドをインターセプト(横取り)したり、実行対象メソッドに動的に処理を追加することができます。
動的プロキシクラスは、Spring FrameworkSeasar2などのAOPを理解するのに必要な知識となります。
Dynamic Proxy Classesなど、かなりわかりやすい解説が書いてあります。

では、ちょっと作って動かしてみましょう。


メイン実行クラス

import java.lang.reflect.Proxy;

public class Aop001 {

  public static void main(String... args) throws Exception {
    
    // 動的プロキシ生成
    MyService f = (MyService) Proxy.newProxyInstance(
        MyService.class.getClassLoader(), 
        new Class[] { MyService.class },
        new FooInvocationHandler(new MyServiceImpl()));
    
    // メイン処理メソッド実行
    f.execute();
  }
}

サービスインターフェイス

public interface MyService {

  // メイン処理メソッド
  void execute();
}

サービスインターフェイスの実装クラス

public class MyServiceImpl implements MyService {

  // メイン処理メソッド
  public void execute() {
    System.out.println("MyServiceImpl で execute処理");
  }
}

InvocationHandlerの実装クラス

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class FooInvocationHandler implements InvocationHandler {
    
  Object target;
  public FooInvocationHandler(Object target) {
    this.target = target;
  }
  
  // メイン処理メソッドの拡張
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    Object ret = null;
    System.out.println("FooInvocationHandler で " + method.getName() + "開始ログ");
    ret = method.invoke(target, args);
    System.out.println("FooInvocationHandler で " + method.getName() + "終了ログ");
    return ret;
  }

}

メイン実行クラスを動かすと以下のように出力されます。

FooInvocationHandler で execute開始ログ
MyServiceImpl で execute処理
FooInvocationHandler で execute終了ログ


ということで、MyServiceImpl#executeメソッド前後にログ出力処理が追加されました。
FooInvocationHandlerを拡張することでサービス#executeメソッドのログ出力、トランザクション開始、例外の補足処理などを追加できますね。