2010-12-10 5 views
11

JDKプロキシクラスは、ファクトリメソッドnewProxyInstance()のインターフェイスのみを受け入れます。JDKのダイナミックプロキシは、インターフェイスでのみ動作します。

回避策がありますか、それとも代替の実装ですか? プロキシで使用するためにメソッドをインタフェースに抽出する必要がある場合、ユースケースは制限されています。実行時に注釈ベースのアクションを適用するためにそれらをラップしたいと思います。

public static <T> T getProxy(T obj) { 
    InvocationHandler ih = new InjectProxy(obj); 
    ClassLoader classLoader = InjectProxy.class.getClassLoader(); 
    return (T) Proxy.newProxyInstance(classLoader, obj.getClass().getInterfaces(), ih); 
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
} 
+1

基本的に、ASMのようなバイトコード・ライブラリーを使用して、クラス・ベースのプロキシーを自分で作成することができます。 –

+0

@Krik、いくつかのユニットテストモックライブラリがこれを行います。必要なメソッドをオーバーライドする派生クラスを作成する必要があります。 (自動または手動で) –

+0

あなたはこの種のことをするように設計されているAspect-Jを考えましたか? –

答えて

15

あなたはこのようにCGLIB使用することができます。しかしエンハンサーをあなたが望むものに変えることができます。

5

利用可能な回避策はありますか..?

ええ。がある。既存のクラスからインタフェースを抽出します。

UPD

あなたには、いくつかの特定のクラスのためにそれを必要とする場合、あなたは、いくつかの「ユニバーサル」のものが必要な場合は@Peter Lawreyが出回っ言ったように、あなたがAOPを使用する必要があります

//interface that already exists 
public interface IDomain { 
    String foo(); 
} 
//your class 
public class Domain implements IDomain{ 
    public String foo(){ 
     return "domain foo"; 
    } 
//method that doesn't placed in IDomain 
    public String bar(){ 
     return "domain bar"; 
    } 
} 
//So you need create new interface with bar() 
//it can extend IDomain 
public interface ExtendedIDomain extends IDomain { 
    public String bar(); 
} 
//than your wrapper factory will be like this 
public class Proxifier { 
    public static ExtendedIDomain getProxy(Domain obj) { 
     InvocationHandler ih = new InjectProxy(obj); 
     ClassLoader classLoader = InjectProxy.class.getClassLoader(); 
     return (ExtendedIDomain) Proxy.newProxyInstance(classLoader, new Class[]{ExtendedIDomain.class}, ih); 
    } 

    static class InjectProxy implements InvocationHandler { 
     private final Domain domain; 
     private InjectProxy(Domain domain){ 
      this.domain = domain; 
     } 

     public String invoke(Object proxy, Method method, Object[] args) throws Throwable{ 
      for(Method m : domain.getClass().getMethods()){ 
       //TODO: check signature(name, args etc) or implement some logic with annotations 
       if(m.getName().equals(method.getName())){ 
        return "wrapped " + m.invoke(domain, args); 
       } 
      } 
      throw new IllegalArgumentException(); 
     } 
    } 
} 
//test 
    public static void main(String[] args) { 
     ExtendedIDomain d = Proxifier.getProxy(new Domain()); 
     System.out.println(d.foo()); 
     System.out.println(d.bar()); 
    } 

のようなSMTを書くことができます。

+1

ありがとうございましたが、私がすでに述べたように: "プロキシで使用できるようにするためにメソッドをインタフェースに抽出する必要がある場合、ユースケースが制限されています" – stacker

+0

@stacker、utilは必要ないようですが、私はこの目的のために自分の投稿を更新しました。 –

2

または代替の実施

あなたはcglibを使用することができます。 CGLIBする代替案の

同様の記事:例えば

import java.lang.reflect.Array; 
import java.lang.reflect.Method; 
import java.lang.reflect.Modifier; 

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


public class AbstractFactory { 

    @SuppressWarnings("unchecked") 
    public static <A> A createDefaultImplementation(Class<A> abstractClass) { 
     Enhancer enhancer = new Enhancer(); 
     enhancer.setSuperclass(abstractClass); 
     enhancer.setCallback(new MethodInterceptor() { 
      public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { 
       if (!Modifier.isAbstract(method.getModifiers())) { 
        return methodProxy.invokeSuper(proxy, args); 
       } else { 
        Class type = method.getReturnType(); 
        if (type.isPrimitive() && !void.class.equals(type)) { 
         return Array.get(Array.newInstance(type, 1), 0); 
        } else { 
         return null; 
        } 
       } 
      } 
     }); 
     return (A) enhancer.create(); 
    } 

    @SuppressWarnings("unchecked") 
    public static <A> A createDefaultImplementation(String className) throws ClassNotFoundException{ 
     return (A) createDefaultImplementation(Class.forName(className)); 
    } 
} 

これはデフォルトの実装方法と抽象クラスを構築することができます:Are there alternatives to cglib?

関連する問題