Java
reflection

java.lang.reflect.Proxyの使い方(1)

More than 3 years have passed since last update.

はじめに

java.lang.reflect.Proxyを利用して、指定したインターフェイスを実装したクラスに対し、そのメソッド呼び出し前後に任意の処理を追加します。こういう場面で使えるんじゃないかな?ってのがありますが、まずは簡単なサンプルを使って実際に動かしてみたいと思います。

まずはProxyを使わないで..

ISome.java
public interface ISome {
    public void doSomething(int val);
}
Some.java
public class Some implements ISome {
    @Override
    public void doSomething(int val) {
        System.out.println(val);
    }
}
Main.java
public class Main {
    public static void main(String[] args) {
        System.out.println("start");

        ISome some = new Some();
        some.doSomething(1000);

        System.out.println("end");
    }
}

敢えて示すまでもないですが、実行結果は以下のようになります。

start
1000
end

Proxyを使ってみる..

SomeProxyクラスを追加します。

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

public class SomeProxy {
    private ISome some;
    private Object proxy;

    private SomeProxy(ISome some) {
        this.some = some;
        this.proxy = Proxy.newProxyInstance(
            ISome.class.getClassLoader(),
            new Class[]{ ISome.class },
            new SomeHandler());
    }

    /**
     * 外部からはこのメソッドを通じてProxyを取得します.
     */
    public static ISome createProxy(ISome some) {
        SomeProxy obj = new SomeProxy(some);
        return ISome.class.cast(obj.proxy);
    }

    /**
     * Proxyのメソッド呼び出しハンドラ.
     */
    private class SomeHandler implements InvocationHandler {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("before: invoke method called..");
            Object o = method.invoke(some, args);
            System.out.println("after: invoke method called..");
            return o;
        }
    }
}

ISomeインターフェイスとその実装のSomeクラスに変更はありません。
呼び出し元のMainクラスを以下のように変更します。

Main.java
public class Main {
    public static void main(String[] args) {
        System.out.println("start");

        ISome some = new Some();
        some.doSomething(1000);

        //Proxyを利用した呼び出しを行います
        ISome proxy = SomeProxy.createProxy(some);
        proxy.doSomething(2000);

        System.out.println("end");
    }
}

実行結果は以下のようになります。
既存のSomeクラスには全く手を加えていないのに処理が追加されました。

start
1000
before: invoke method called..
2000
after: invoke method called..
end

次回

「こういう場面で使えるんじゃないかな?」を具体的に書こうかなと思っています。