一步一步想Java动态代理

版本一

试着只去看API,根据自己的理解,写出了Java动态代理的第一个版本

publicclass DynamicProxyTest

{

    publicstaticinterface IWorker {

       public String work();

    }

   

    publicstaticclass Worker implements IWorker{

        public String work() {

           System.out.println("working...");

           return"hello, work";

        }

    }

   

    publicstaticclass Invocator implements InvocationHandler {

       @Override

       public Object invoke(Object proxy, Method method, Object[] args)

              throws Throwable {

           System.out.println("before work...");

           String s = (String)method.invoke(proxy);

           System.out.println("after work...");

           returns;

       }

    }

    publicstaticvoid main(String[] args) {

       InvocationHandler invocator = new Invocator();

       IWorker proxyWorker = (IWorker)Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(), new Class[]{IWorker.class}, invocator);

       System.out.println(proxyWorker.work());

    }

}

在不知道具体怎么使用动态代理的情况下,主要围绕Proxy.newProxyInstance这个方法猜测用法的。这个方法接收三个参数,如下:

ClassLoader loader:这个好办,把当前类加载器传入即可。

Class<?>[] interfaces:生成的代理类有哪些方法,是通过传入哪些接口类决定的(这也表明了java动态代理是基于接口的);这个参数也没有疑问,直接把我们要代理的接口传入即可:new Class[]{IWorker.class}

InvocationHandler h:实际上在实现InvocationHandler的时候不太清楚怎么实现,主要是不清楚接口中的Object proxy代表什么,于是写成了下面的样子;直接new了一个该实现类当参数传入了。

publicstaticclass Invocator implements InvocationHandler {

       @Override

       public Object invoke(Object proxy, Method method, Object[] args)

              throws Throwable {

           System.out.println("before work...");

           String s = (String)method.invoke(proxy);

           System.out.println("after work...");

           returns;

       }

    }

不出所料,挂掉了,而且错误信息根本停不下来啊。

想了一下,最有可能出问题的地方是:不太清楚InvocationHandler接口中接口方法invoke(Object proxy, Method method, Object[] args)中,参数proxy究竟是一个什么对象呢?

Proxy.newProxyInstance的源代码(SUN JDK:

第一步: 

/*

         * Look up or generate the designated proxy class.

         */

        Class<?> cl = getProxyClass0(loader, interfaces);

生成代理类的字节码,具体怎么生成的先不管。

第二步:

/** parameter types of a proxy class constructor */

privatefinalstatic Class[] constructorParams =

        { InvocationHandler.class };

final Constructor<?> cons = cl.getConstructor(constructorParams);

获取代理类的构造函数类(构造函数在JVM中使用Constructor类表示)。

第三部:

cons.newInstance(new Object[] {h} );

构造函数+构造函数参数生成代理类实例,一个我们需要的代理类就生成的。

现在关于生成的代理类,有以下几点可以确定:

1、代理类以一个InvocationHander实例为参数,该实例是通过Proxy.newProxyInstance传入的。

2、代理类具有它所代理的接口的所有方法,比如,Iworker的代理类,就一定会有一个work()方法,因为我们将来还要通过代理类调用work()方法的。

所以,IWorker生成的代理类大体长这样:

/**

     * 模仿JDK动态生成的代理类

     * JavaIWorker生成的代理类,应该类似我们这里实现的该类。

     * 只不过JDK使用字节码技术动态生成该类,因此灵活性更高。

     * @author Grucee

     */

    publicstaticclass ImitationProxy implements IWorker{

       private InvocationHandler handler;

       public ImitationProxy(InvocationHandler handler) {

           this.handler = handler;

       }

      

       @Override

       public String work() {

           returnnull;

       }

      

    }

那么它的work方法又是怎么实现呢,结合InvocationHandler的接口,该方法应该是知己调用InvocationHandlerinvoke方法:

public String work() {

           return handler.invoke(this, method, args);

       }

上面的代码是编译不通过的,因为我们看似无法获取到methodargs参数。其实不然,代理类怎么知道自己是有哪些方法要实现的,肯定是通过Proxy.newProxyInstance第二个参数(接口类数组),然后通过Class:getDeclaredMethods()获取到有哪些方法要实现,所以它在生成代理类的work方法的时候,肯定就知道它是Iworker.class. getDeclaredMethods[]中的work方法了;当然也就知道这个方法有哪些参数了。

至此,我们终于搞清楚了InvocationHandler:invoke(Object proxy, Method method, Object[] args)中,参数proxy代表什么?它代码的是JDK动态生成的代理类的一个实例。

再思考一个问题,动态生成的代理类会干活么?不会,只有我们自己的IWorker实现类Worker才知道work方法要做什么,所以我们必须要有一个Worker实例才能真正完成工作。因此有了下面的版本二。

版本二

publicclass DynamicProxyTest

{

    publicstaticinterface IWorker {

       public String work();

    }

   

    publicstaticclass Worker implements IWorker{

        public String work() {

           System.out.println("working...");

           return"hello, work";

        }

    }

   

   

    publicstaticclass Invocator implements InvocationHandler {

        private IWorker worker;

        public Invocator(IWorker worker) {

           this.worker = worker;

        }

       

       @Override

       public Object invoke(Object proxy, Method method, Object[] args)

              throws Throwable {

           System.out.println("before work...");

           String s = (String)method.invoke(worker);

           System.out.println("after work...");

           returns;

       }

    }

    publicstaticvoid main(String[] args) {

       IWorker worker = new Worker();

       InvocationHandler invocator = new Invocator(worker);

       IWorker proxyWorker = (IWorker)Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(), new Class[]{IWorker.class}, invocator);

       System.out.println(proxyWorker.work());

    }

}

我们让InvocationHandler持有一个Worker实例,有实例、又有实例的方法,通过反射就可以完成具体的工作了。并且它可以在做具体工作前、后做任意的处理。

版本三

从上面版本二可以看出,要获取一个接口的代理类,我们要提供两个参数:接口类和实现类的一个实例。

如果接口类和实现类的包名再加一些约束条件,即通过接口类可以知道实现类的约束条件,那样我们就可以传入一个接口类,就可以返回一个代理类了。比如最简单的约束条件:接口类和实现类在同一包名下,接口类以IXXX命名,实现类以XXXImpl命名。

publicclass DynamicProxyTest

{

    publicstaticinterface IWorker {

       public String work();

    }

   

    publicstaticclass IWorkerImpl implements IWorker{

        public String work() {

           System.out.println("working...");

           return"hello, work";

        }

    }

   

   

    publicstaticclass Invocator implements InvocationHandler {

        private Object o;

        private Invocator(Object o) {

           this.o = o;

        }

       

       @Override

       public Object invoke(Object proxy, Method method, Object[] args)

              throws Throwable {

           System.out.println("before work...");

           String s = (String)method.invoke(o);

           System.out.println("after work...");

           returns;

       }

    }

   

    publicstatic Object getProxy(Class<?> iface) throws Exception {

        String ifaceName = iface.getName();

        String[] ifaceSplitted = ifaceName.split("[.]");

       

        String packageName = "";

        intlastSplit = ifaceName.lastIndexOf(".");

        if (lastSplit != -1) {

           packageName = ifaceName.substring(0, lastSplit);

        }

       

        String className = ifaceSplitted[ifaceSplitted.length - 1] + "Impl";

        if (!packageName.equals("")) {

           className = packageName + "."className;

        }

       

        //实例化实现类

        Object o = Class.forName(className).newInstance();

        InvocationHandler invocator = new Invocator(o);

        return Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(), new Class[]{iface}, invocator);

    }

   

    publicstaticvoid main(String[] args) throws Exception {

       IWorker worker = (IWorker)getProxy(IWorker.class);

       worker.work();

    }

   

    /**

     * 模仿JDK动态生成的代理类

     * JavaIWorker生成的代理类,应该类似我们这里实现的该类。

     * 只不过JDK使用字节码技术动态生成该类,因此灵活性更高。

     * @author Grucee

     */

    publicstaticclass ImitationProxy implements IWorker{

       private InvocationHandler handler;

      

       public ImitationProxy(InvocationHandler handler) {

           this.handler = handler;

       }

      

       @Override

       public String work() {

           /**

            * Object proxy:这个好办,传入this

            * Method method:代理类怎么知道自己是有哪些方法要实现的,肯定是通过

            * Proxy.newProxyInstance第二个参数(接口类数组),然后通过

            * Class:getDeclaredMethods()获取到有哪些方法要实现,所以它在生成代理类的work方法

            * 的时候,肯定是知道Method是哪个了。

            * Object[] args:方法的参数

            */

           //return handler.invoke(this, method, args);

           return"";

       }

      

    }

}

 

 

你可能感兴趣的:(java,动态代理)