AOPの基礎 動的プロキシを触る
動的プロキシクラスを使用することによって、実行時にインターフェイスを介して実行対象メソッドをインターセプト(横取り)したり、実行対象メソッドに動的に処理を追加することができます。
動的プロキシクラスは、Spring Framework、Seasar2などの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メソッドのログ出力、トランザクション開始、例外の補足処理などを追加できますね。