【Java】【AOP】自作のインターセプター

■ はじめに

http://d.hatena.ne.jp/tbpg/20121125/1353868194
を参考に、自作のインターセプターを試みる。
この機能を応用すれば、関数の始まりと終わりにログが意識しなくても張れる。

■ 関連用語

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

インターセプターで検索すると、「アスペクト指向プログラミング(Aspect-Oriented Programming)」なども
関わってくる。
詳細は、以下の関連記事を参照のこと。
https://blogs.yahoo.co.jp/dk521123/29124525.html

■ サンプル

 * 関数の始まりに「メソッド名と引数」と
  関数の終わりに「メソッド名と戻り値」を標準出力するインターセプターを作成してみた

インターセプター対象のクラスとインターフェイス

ITarget.java
public interface ITarget {
   String getValue();

   void setValue(String value);
}
TargetClass.java
public class TargetClass implements ITarget {
   private String value = null;

   public String getValue() {
      return this.value;
   }

   public void setValue(String value) {
      this.value = value;
   }
}

!キモ! インターセプター

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

public class SampleIntercepter implements InvocationHandler {
   Object target;

   private SampleIntercepter(Object target) {
      this.target = target;
   }

   @SuppressWarnings({ "rawtypes", "unchecked" })
   public static <T> T getProxyInstance(T instance) {
      Class<? extends Object> clazz = instance.getClass();
      // 対象クラスが実装するインターフェースのリスト
      Class[] classes = clazz.getInterfaces();
      SampleIntercepter intercepter = new SampleIntercepter(instance);
      T proxyInstance = (T) Proxy.newProxyInstance(clazz.getClassLoader(), classes, intercepter);
      return proxyInstance;
   }

   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      this.enter(method, args);

      // 実際のコードを呼び出し
      Object result = method.invoke(this.target, args);

      this.exit(method, result);
      return result;
   }

   private void enter(Method method, Object[] args) {
      System.out.print("[Enter] " + method.getName());
      if (args != null) {
         for (Object arg : args) {
            System.out.print(" Argument : " + arg.toString());
         }   
      }
      System.out.println();
   }

   private void exit(Method method, Object result) {
      System.out.print("[Exit] " + method.getName());
      if (result != null) {
         System.out.print(" Return Value : " + result.toString());
      }
      System.out.println();
   }
}

使用者

TargetClass.java
public class Main {
   public static void main(String[] args) {
      ITarget targetClass = SampleIntercepter.getProxyInstance(new TargetClass());
      targetClass.setValue("Dummy");
      String result = targetClass.getValue();
      System.out.println("End " + result);
   }
}

出力結果

[Enter] setValue Argument : Dummy
[Exit] setValue
[Enter] getValue
[Exit] getValue Return Value : Dummy
End Dummy