4

如何在不创建实现它的类的情况下为接口创建代理?

我有一个具体的例子:我有一个接口,Contact,需要创建一个代理对象来充当联系人。这个代理对象将用于运行一些 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() 方法的参数将是一个接口。

谢谢

4

5 回答 5

8

可以使用的方法newProxyInstancejava.lang.reflect.Proxy前任:

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

iClazz是您的接口的类,并且YourInvocationHandlerjava.lang.reflect.InvocationHandler

于 2012-09-19T16:40:44.403 回答
2

commons-proxy旨在简化任务。

你想要的是一个调用者代理(没有目标对象)。所以你可以使用:

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

并且您invoker必须实现该Invoker接口,该接口的invoke方法将在每次方法调用时被调用。(这里是“调用”这个词的 4 倍)

请注意,commons-proxy 使用首选的底层代理机制 - 在上面的示例中,它是 javassist。


但是,您似乎需要代理来进行模拟。使用mockito,这很简单:

YourInterface yourMock = mock(YourInterface.class);
when(yourMock.someMethod()).thenReturn(yourPreferredResult);
于 2010-10-05T10:12:31.303 回答
1

如果您只对模拟感兴趣,我建议您使用框架。

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

要自己创建代理,您可以使用该类java.lang.reflect.Proxy

于 2010-10-05T10:11:29.700 回答
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 是由对您的调用的递归调用产生的。

于 2010-10-31T21:27:02.867 回答
0

java.lang.reflect.proxyExampledepot 有一个简单的片段,说明如何基于http://exampledepot.8waytrips.com/egs/java.lang.reflect/ProxyClass.html创建接口代理

您只需要invoke(Object proxy, Method m, Object[] args)在自己的代码中提供功能即可。


编辑:根据评论,您不想要的类似乎是接口类,而不是实现类。在这种情况下,无法绕过字节码操作。您可能想查看包含片段编译器的 Javassist。

于 2010-10-05T10:40:14.717 回答