2010-10-05 31 views
3

如何創建接口的代理而不創建實現它的類?如何在Java中創建接口的代理?

我有一個具體的例子:我有一個接口,聯繫人,並需要創建一個作爲聯繫人的代理對象。此代理對象將用於運行一些TestNG測試。

我嘗試過使用JDK方法,但只能找到需要該接口的實際實現的示例。

我還發現,jasssist可以幫助我解決這個問題,並試圖實現一個簡單的例子,似乎一直工作,直到我得到一個內存不足的錯誤。這裏是我正在做的一個片段:

import javassist.util.proxy.MethodFilter; 
import javassist.util.proxy.MethodHandler; 
import javassist.util.proxy.ProxyFactory 

protected final T createMock(final Class<T> clazz) { 
    final ProxyFactory factory = new ProxyFactory(); 
    factory.setInterfaces(new Class[] { clazz }); 
    factory.setFilter(new MethodFilter() { 
     public final boolean isHandled(final Method m) { 
      // ignore finalize() 
      return !m.getName().equals("finalize"); 
     } 
    }); 

    final MethodHandler handler = createDefaultMethodHandler(); 
    try { 
     return (T) factory.create(new Class<?>[0], new Object[0], handler); 
    } catch (final Exception e) { 
     e.printStackTrace(); 
    } 
    return null; 
} 
private MethodHandler createDefaultMethodHandler() { 
    return new MethodHandler() { 
     public final Object invoke(final Object self, 
       final Method thisMethod, final Method proceed, 
       final Object[] args) throws Throwable { 
      System.out.println("Handling " + thisMethod 
        + " via the method handler"); 
      return thisMethod.invoke(self, args); 
     } 
    }; 
} 

請記住,createMock()方法的參數將是一個接口。

謝謝

+0

一個實例你爲什麼不理電話敲定?也許這與你的OutOfMemory異常有關! – Arne 2010-10-05 12:48:18

+0

如果我考慮finalize()方法,則仍會出現該錯誤。我認爲問題在其他地方,因爲我在使用javassist和commons-proxy時遇到了同樣的錯誤。目前,我認爲我會爲每個需要測試的接口提供一個簡單的實現,因爲我在這個問題上投入了一些時間並可以使其工作。 – virgium03 2010-10-05 12:56:39

回答

1

如果你只是在嘲笑有趣,我會建議使用框架。

EasyMock(http://easymock.org/)或JMock(http://www.jmock.org/)可能適合。

要自己創建代理,您可以使用類java.lang.reflect.Proxy

+0

我看着嘲笑的框架,並嘗試EasyMock,但我只是想創建一個代理,而不是設置一些期望,行爲等。 – virgium03 2010-10-05 10:52:52

1

commons-proxy旨在簡化任務。

你想要的是一個調用者代理(沒有目標對象)。所以,你可以使用:

ProxyFactory factory = new JavassistProxyFactory(); 
Object result = 
     factory.createInvokerProxy(invoker, new Class[] {YourInterface.class}); 

而且你invoker必須實現Invoker接口,其invoke方法將被調用的每個方法調用。 (這裏是「invoke」的4倍)

請注意,commons-proxy使用首選的底層代理機制 - 在上例中它是javassist。


但是,您似乎需要用於嘲笑目的的代理。隨着mockito這是那麼容易,因爲:

YourInterface yourMock = mock(YourInterface.class); 
when(yourMock.someMethod()).thenReturn(yourPreferredResult); 
+0

我會嘗試公共代理。請注意,我提供的代碼片段很有用,但測試需要很長時間才能運行,因此會拋出大量的InvocationTargetException,然後出現OutOfMemory。 – virgium03 2010-10-05 10:59:48

0

Exampledepot對如何在http://exampledepot.8waytrips.com/egs/java.lang.reflect/ProxyClass.html

你只需要在自己的代碼提供了invoke(Object proxy, Method m, Object[] args)功能創建一個基於java.lang.reflect.proxy接口代理一個簡單的片斷。


編輯:根據意見,似乎你不希望類是接口類,而不是實現類。在那種情況下,字節碼操作是沒有辦法的。你可能想看看包含代碼片段編譯器的Javassist。

+0

謝謝,但這個例子需要一個接口的實現,我不想創建一個實際的實現。 – virgium03 2010-10-05 10:51:51

+0

這是我想要避免的。 – virgium03 2010-10-05 11:00:34

0

在你的代碼中,我做了以下

//    return thisMethod.invoke(self, args); 
      return null; 

和我得到了以下結果

Handling public abstract void org.rege.instruments.IPerson.setName(java.lang.String) via the method handler 

難道這就是你想要的? 正如你所看到的,OutOfMemory是通過對你的調用進行遞歸調用產生的。

8

您可以使用java.lang.reflect.Proxy的方法newProxyInstance。 例如:

Proxy.newProxyInstance(iClazz.getClassLoader(), 
     new Class[]{iClazz}, 
     new YourInvocationHandler()) 

iClazz是班級的接口和YourInvocationHandler的是java.lang.reflect.InvocationHandler