正 文

用Java动态代理来创建包装器


www.7dspace.com  更新日期:2006-1-9 5:19:15  七度空间


使用动态代理

下面的代码演示了用动态代理来创建一个BuilderRobot时所必需的类。注意我们创建的这个 BuilderRobotInvocationHandler类甚至根本没有实现Robot接口。相反,它实现了 java.lang.reflect.InvocationHandler,只提供了一个invoke方法。代理对象上的任何方法调用都要通过这一方法进行。观察invoke的主体,我们发现它会检查准备调用的方法的名称。如果这个名称是workOn,第二个参数就切换成一个非破坏性的工具。

然而,我们得到的仍然只是一个具有invoke方法的InvocationHandler,而不是我们真正想要的Robot对象。动态代理真正的魅力要到创建实际的Robot实例时才能反映出来。在源代码的任何地方,我们都没有定义一个Robot包装器或者子类。虽然如此,我们最终仍能获得一个动态创建的类,它通过调用BuilderRobotInvocationHandler的静态方法createBuilderRobot中的代码片断,从而实现了Robot接口,并集成了Builder工具过滤器。


import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
 
public class BuilderRobotInvocationHandler implements InvocationHandler {
    private Robot wrapped;
    public BuilderRobotInvocationHandler(Robot r) {
        wrapped = r;
    }
    public Object invoke(Object proxy, Method method, Object[] args)
           throws Throwable {
        if ("workOn".equals(method.getName())) {
            args[1] = Tool.RATCHET;
        }
        return method.invoke(wrapped, args);
    }
    public static Robot createBuilderRobot(Robot toWrap) {
        return (Robot)(Proxy.newProxyInstance(Robot.class.getClassLoader(),
            new Class[] {Robot.class},
                new BuilderRobotInvocationHandler(toWrap)));
    }
    public static final void main(String[] args) {
        Robot r = createBuilderRobot(new MyRobot());
        r.workOn("scrap", Tool.CUTTING_TORCH);
    }
}

createBuilderRobot中的代码表面上很复杂,但它的作用其实很简单,就是告诉Proxy类用一个指定的类加载器来动态创建一个对象,该对象要实现指定的接口(本例为Robot),并用提供的InvocationHandler来代替传统的方法主体。结果对象在一个instanceof Robot测试中返回true,并提供了在实现了Robot接口的任何类中都能找到的方法。

有趣的是,在BuilderRobotInvocationHandler类的invoke方法中,完全不存在对Robot接口的引用。InvocationHandlers并不是它们向其提供了“代理方法实现”的接口所专用的,你完全可以写一个InvocationHandler,并将其作为众多代理类的后端来使用。

4页,页码:[1] [2] [3] [4] 

上一篇:用JGraph轻松表示图形数据
下一篇:Blog设计的7个趋势
作者:  来源:开发者在线 ( 责任编辑:7dspace )
收藏此页】【打印】【关闭
站 内 搜 索
 

热 点 导 读
特 别 推 荐