论坛首页 Java企业应用论坛

窥探EasyMock(3)动态代理技术

浏览 1562 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-01-05   最后修改:2009-01-06

EasyMock的实现使用了动态代理(Dynamic Proxy) 技术。动态代理工具是 java.lang.reflect 包的一部分,在 JDK 1.3 版本中添加到 JDK,它允许程序创建代理对象,代理对象能实现一个或多个已知接口,并用反射代替内置的虚方法分派,分派对接口方法的调用。这个过程允许实现“截取”方法调用,重新路由它们或者动态地添加功能。

 

动态代理机制的核心是InvocationHandler 接口:

 

public interface InvocationHandler {
    Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}
 

例子,下面这个handler为所有的方法调用添加了log:

 

public class LogEnabler<T> implements InvocationHandler {

        private T t;

        public LogEnabler(T t) {
            this.t = t;
        }

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            LOG.info("Before invocation to " + method.getName() + ".");
            Object result = method.invoke(t, args);
            LOG.info("After invocation to " + method.getName() + ".");
            return result;
        }

    }

 

看到了AOP的影子了么?事实上如structs2中interceptor的实现就是使用了动态代理技术。

 

同样,EasyMock的核心技术也是使用了动态代理,可以看到createMock方法的代码如下:

 

public <T> T createMock(Class<T> toMock) {
        try {
            state.assertRecordState();
            IProxyFactory<T> proxyFactory = createProxyFactory(toMock);
            return proxyFactory.createProxy(toMock, new ObjectMethodsFilter(
                    toMock, new MockInvocationHandler(this), null));
        } catch (RuntimeExceptionWrapper e) {
            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
        }
}

 

它使用了ProxyFactory来为被mock的类创建了一个代理对象。ProxyFactory的实现如下:

 

public class JavaProxyFactory<T> implements IProxyFactory<T> {
    @SuppressWarnings("unchecked")
    public T createProxy(Class<T> toMock, InvocationHandler handler) {
        return (T) Proxy.newProxyInstance(toMock.getClassLoader(),
                new Class[] { toMock }, handler);
    }
}

 

显而易见,创建mock对象最核心的就是拦截方法调用,用期望的行为和返回结果代替。那就来看看ObjectMethodsFilter这个拦截类。这个类拦截了Object类中三个基本方法的调用,而把被mock类其它方法的调用转发至MockInvocationHandler这个delegate处理:

 

public final Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        if (equalsMethod.equals(method)) {
            return Boolean.valueOf(proxy == args[0]);
        }
        if (hashCodeMethod.equals(method)) {
            return Integer.valueOf(System.identityHashCode(proxy));
        }
        if (toStringMethod.equals(method)) {
            return mockToString(proxy);
        }
        return delegate.invoke(proxy, method, args);
}

 

关于EasyMock对于record,replay和verify的具体实现,且听下回分解。

论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics