98

ドキュメントによると:

[ java.lang.reflect.]Proxyは、動的プロキシクラスとインスタンスを作成するための静的メソッドを提供します。また、これらのメソッドによって作成されるすべての動的プロキシクラスのスーパークラスでもあります。

このnewProxyMethodメソッド(動的プロキシの生成を担当)には、次のシグネチャがあります。

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
                             throws IllegalArgumentException

残念ながら、これにより、(特定のインターフェイスを実装するのではなく)特定の抽象クラスを拡張する動的プロキシを生成できなくなります。これは、「すべての動的プロキシのスーパークラス」であると考えると理にかなっており、それによって別のクラスがスーパークラスになるのを防ぎます。java.lang.reflect.Proxy

したがって、特定の抽象クラスから継承java.lang.reflect.Proxyする動的プロキシを生成し、抽象メソッドへのすべての呼び出しを呼び出しハンドラーにリダイレクトできる代替手段はありますか?

たとえば、抽象クラスがあるとしますDog

public abstract class Dog {

    public void bark() {
        System.out.println("Woof!");
    }

    public abstract void fetch();

}

次のことができるクラスはありますか?

Dog dog = SomeOtherProxy.newProxyInstance(classLoader, Dog.class, h);

dog.fetch(); // Will be handled by the invocation handler
dog.bark();  // Will NOT be handled by the invocation handler
4

2 に答える 2

131

これは、 Javassist(を参照)またはCGLIBを使用して実行できます。ProxyFactory

Javassistを使用したAdamの例:

私(Adam Paynter)は、Javassistを使用してこのコードを作成しました。

ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(Dog.class);
factory.setFilter(
    new MethodFilter() {
        @Override
        public boolean isHandled(Method method) {
            return Modifier.isAbstract(method.getModifiers());
        }
    }
);

MethodHandler handler = new MethodHandler() {
    @Override
    public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
        System.out.println("Handling " + thisMethod + " via the method handler");
        return null;
    }
};

Dog dog = (Dog) factory.create(new Class<?>[0], new Object[0], handler);
dog.bark();
dog.fetch();

これはこの出力を生成します:

横糸!
メソッドハンドラを介したpublicabstractvoid mock.Dog.fetch()の処理
于 2010-07-20T16:32:23.273 に答える
-9

このような場合にできることは、抽象クラスの既存のメソッドに呼び出しをリダイレクトするプロキシハンドラーを用意することです。

もちろんコーディングする必要がありますが、非常に簡単です。プロキシを作成するには、彼にを与える必要がありますInvocationHandlerinvoke(..)その後、呼び出しハンドラのメソッドでメソッドタイプを確認するだけで済みます。ただし、注意してください。メソッドの型を、抽象クラスの宣言された型ではなく、ハンドラーに関連付けられた基になるオブジェクトと照合する必要があります。

例としてあなたの犬のクラスを取り上げると、あなたの呼び出しハンドラーのinvokeメソッド次のようになります(.. well ...と呼ばれる既存の関連付けられた犬のサブクラスを使用dog

public void invoke(Object proxy, Method method, Object[] args) {
    if(!Modifier.isAbstract(method.getModifiers())) {
        method.invoke(dog, args); // with the correct exception handling
    } else {
        // what can we do with abstract methods ?
    }
}

しかし、私が不思議に思うことがあります:私はdogオブジェクトについて話しました。ただし、Dogクラスは抽象であるため、インスタンスを作成できないため、既存のサブクラスがあります。さらに、プロキシソースコードを厳密に調べると、(Proxy.java:362で)インターフェイスを表さないClassオブジェクトのプロキシを作成できないことがわかります。

ですから、現実とは別に、あなたがやりたいことは完全に可能です。

于 2010-07-20T15:46:04.810 に答える