Javaでインタフェースのメソッドを動的に実装する方法を教えてください

Javaでは、インタフェースのメソッドを動的に実装するために、動的プロキシ手法を使用できます。動的プロキシとは、実行時に特定のインタフェースを実装する代理クラスを作成できるようにする設計パターンです。

Javaでは、インターフェイスベースの動的プロキシとクラスベースの動的プロキシという2つの方法で動的プロキシを実装できます。

  1. インターフェースベースの動的プロキシ:Javaでは、インターフェースベースの動的プロキシを実現するための、専用クラスのProxyとインターフェースのInvocationHandlerが用意されています。InvocationHandlerインターフェースを実装し、そのinvokeメソッドをオーバーライドすることにより、invokeメソッド内でインターフェースメソッドの動的処理を実現できます。その後、ProxyクラスのstaticメソッドであるnewProxyInstanceを使用して、プロキシオブジェクトを作成できます。

以下にサンプルコードを示します。

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

interface HelloWorld {
    void sayHello();
}

class HelloWorldImpl implements HelloWorld {
    @Override
    public void sayHello() {
        System.out.println("Hello World!");
    }
}

class HelloWorldProxy implements InvocationHandler {
    private Object target;

    public HelloWorldProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before invoking sayHello method");
        Object result = method.invoke(target, args);
        System.out.println("After invoking sayHello method");
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        HelloWorld helloWorld = new HelloWorldImpl();

        HelloWorld proxy = (HelloWorld) Proxy.newProxyInstance(
                HelloWorld.class.getClassLoader(),
                new Class[]{HelloWorld.class},
                new HelloWorldProxy(helloWorld));

        proxy.sayHello();
    }
}
  1. CGLibを利用する動的クラスベースのプロキシ:インターフェースベースの動的プロキシに加え、JavaはCGLibというライブラリを用いた、クラスベースの動的プロキシを提供しています。CGLibは、指定されたクラスのサブクラスを動的に、ランタイム時に生成できる、強力で高性能なコード生成ライブラリです。対象クラスを継承し、そのメソッドをオーバーライドすることで、サブクラス内で対象クラスのメソッドに対する動的な処理を実現します。

サンプルコードを次に示します。

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

class HelloWorld {
    public void sayHello() {
        System.out.println("Hello World!");
    }
}

class HelloWorldInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before invoking sayHello method");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("After invoking sayHello method");
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(HelloWorld.class);
        enhancer.setCallback(new HelloWorldInterceptor());

        HelloWorld proxy = (HelloWorld) enhancer.create();

        proxy.sayHello();
    }
}

インターフェースベースのダイナミック型プロキシ、クラスベースのダイナミック型プロキシのどちらでも、代理オブジェクトにインターフェースメソッドの動的な取り扱いを実装できます。

bannerAds