动态代理invocationHandler的invoke()问题

如下的内容部分参考了网络上的内容,在此对原做者表示感谢! 

        Java中动态代理的实现,关键就是这两个东西:Proxy、InvocationHandler,下面从InvocationHandler接口中的invoke方法入手,简单说明一下Java如何实现动态代理的。 
        首先,invoke方法的完整形式以下: 

Java代码   收藏代码
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable  
    {  
  
        method.invoke(obj, args);  
  
        return null;  
    }  

        首先猜想一下,method是调用的方法,即须要执行的方法;args是方法的参数;proxy,这个参数是什么?以上invoke()方法的实现便是比较标准的形式,咱们看到,这里并无用到proxy参数。查看JDK文档中Proxy的说明,以下: 

Java代码   收藏代码
A method invocation on a proxy instance through one of its proxy interfaces will be dispatched to the invoke method of the instance's invocation handler, passing the proxy instance,a java.lang.reflect.Method object identifying the method that was invoked, and an array of type Object containing the arguments.  

        由此能够知道以上的猜想是正确的,同时也知道,proxy参数传递的便是代理类的实例。 

        为了方便说明,这里写一个简单的例子来实现动态代理。 

       

Java代码   收藏代码
//抽象角色(动态代理只能代理接口)  
public interface Subject {  
      
    public void request();  
}  


Java代码   收藏代码
//真实角色:实现了Subject的request()方法  
public class RealSubject implements Subject{  
      
    public void request(){  
        System.out.println("From real subject.");  
    }  
}  


Java代码   收藏代码
//实现了InvocationHandler  
public class DynamicSubject implements InvocationHandler  
{  
    private Object obj;//这是动态代理的好处,被封装的对象是Object类型,接受任意类型的对象  
  
    public DynamicSubject()  
    {  
    }  
  
    public DynamicSubject(Object obj)  
    {  
        this.obj = obj;  
    }  
  
    //这个方法不是咱们显示的去调用  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable  
    {  
        System.out.println("before calling " + method);  
  
        method.invoke(obj, args);  //----->这一步详看下一篇文章,java 经过反射机制调用某个类的方法,看完你会了解的。
  
        System.out.println("after calling " + method);  
  
        return null;  
    }  
  
}  


Java代码   收藏代码
//客户端:生成代理实例,并调用了request()方法  
public class Client {  
  
    public static void main(String[] args) throws Throwable{  
        // TODO Auto-generated method stub  
  
        Subject rs=new RealSubject();//这里指定被代理类  
        InvocationHandler ds=new DynamicSubject(rs);  
        Class<?> cls=rs.getClass();  
          
        //如下是一次性生成代理  
          
        Subject subject=(Subject) Proxy.newProxyInstance(  
                cls.getClassLoader(),cls.getInterfaces(), ds);  
          
        //这里能够经过运行结果证实subject是Proxy的一个实例,这个实例实现了Subject接口  
        System.out.println(subject instanceof Proxy);  
          
        //这里能够看出subject的Class类是$Proxy0,这个$Proxy0类继承了Proxy,实现了Subject接口  
        System.out.println("subject的Class类是:"+subject.getClass().toString());  
          
        System.out.print("subject中的属性有:");  
          
        Field[] field=subject.getClass().getDeclaredFields();  
        for(Field f:field){  
            System.out.print(f.getName()+", ");  
        }  
          
        System.out.print("\n"+"subject中的方法有:");  
          
        Method[] method=subject.getClass().getDeclaredMethods();  
          
        for(Method m:method){  
            System.out.print(m.getName()+", ");  
        }  
          
        System.out.println("\n"+"subject的父类是:"+subject.getClass().getSuperclass());  
          
        System.out.print("\n"+"subject实现的接口是:");  
          
        Class<?>[] interfaces=subject.getClass().getInterfaces();  
          
        for(Class<?> i:interfaces){  
            System.out.print(i.getName()+", ");  
        }  
  
        System.out.println("\n\n"+"运行结果为:");  
        subject.request();  
    }  
}  


Xml代码   收藏代码
运行结果以下:此处省略了包名,***代替  
true  
subject的Class类是:class $Proxy0  
subject中的属性有:m1, m3, m0, m2,   
subject中的方法有:request, hashCode, equals, toString,   
subject的父类是:class java.lang.reflect.Proxy  
subject实现的接口是:cn.edu.ustc.dynamicproxy.Subject,   
  
运行结果为:  
before calling public abstract void ***.Subject.request()  
From real subject.  
after calling public abstract void ***.Subject.request()  


PS:这个结果的信息很是重要,至少对我来讲。由于我在动态代理犯晕的根源就在于将上面的subject.request()理解错了,至少是被表面所迷惑,没有发现这个subject和Proxy之间的联系,一度纠结于最后调用的这个request()是怎么和invoke()联系上的,而invoke又是怎么知道request存在的。其实上面的true和class $Proxy0就能解决不少的疑问,再加上下面将要说的$Proxy0的源码,彻底能够解决动态代理的疑惑了。 

        从以上代码和结果能够看出,咱们并无显示的调用invoke()方法,可是这个方法确实执行了。下面就整个的过程进行分析一下: 

        从Client中的代码看,能够从newProxyInstance这个方法做为突破口,咱们先来看一下Proxy类中newProxyInstance方法的源代码: 

Java代码   收藏代码
public static Object newProxyInstance(ClassLoader loader,  
        Class<?>[] interfaces,  
        InvocationHandler h)  
throws IllegalArgumentException  
{  
    if (h == null) {  
        throw new NullPointerException();  
    }  
  
    /* 
     * Look up or generate the designated proxy class. 
     */  
    Class cl = getProxyClass(loader, interfaces);  
  
    /* 
     * Invoke its constructor with the designated invocation handler. 
     */  
    try {  
           /* 
            * Proxy源码开始有这样的定义: 
            * private final static Class[] constructorParams = { InvocationHandler.class }; 
            * cons便是形参为InvocationHandler类型的构造方法 
           */  
        Constructor cons = cl.getConstructor(constructorParams);  
        return (Object) cons.newInstance(new Object[] { h });  
    } catch (NoSuchMethodException e) {  
        throw new InternalError(e.toString());  
    } catch (IllegalAccessException e) {  
        throw new InternalError(e.toString());  
    } catch (InstantiationException e) {  
        throw new InternalError(e.toString());  
    } catch (InvocationTargetException e) {  
        throw new InternalError(e.toString());  
    }  
}  


        Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)作了如下几件事.
        (1)根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces)建立代理类$Proxy0.$Proxy0类 实现了interfaces的接口,并继承了Proxy类. 
        (2)实例化$Proxy0并在构造方法中把DynamicSubject传过去,接着$Proxy0调用父类Proxy的构造器,为h赋值,以下: 

Java代码   收藏代码
class Proxy{  
    InvocationHandler h=null;  
    protected Proxy(InvocationHandler h) {  
        this.h = h;  
    }  
    ...  
}  


        来看一下这个继承了Proxy的$Proxy0的源代码: 

Java代码   收藏代码
public final class $Proxy0 extends Proxy implements Subject {  
    private static Method m1;  
    private static Method m0;  
    private static Method m3;  
    private static Method m2;  
  
    static {  
        try {  
            m1 = Class.forName("java.lang.Object").getMethod("equals",  
                    new Class[] { Class.forName("java.lang.Object") });  
  
            m0 = Class.forName("java.lang.Object").getMethod("hashCode",  
                    new Class[0]);  
  
            m3 = Class.forName("***.RealSubject").getMethod("request",  
                    new Class[0]);  
  
            m2 = Class.forName("java.lang.Object").getMethod("toString",  
                    new Class[0]);  
  
        } catch (NoSuchMethodException nosuchmethodexception) {  
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());  
        } catch (ClassNotFoundException classnotfoundexception) {  
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());  
        }  
    } //static  
  
    public $Proxy0(InvocationHandler invocationhandler) {  
        super(invocationhandler);  
    }  
  
    @Override  
    public final boolean equals(Object obj) {  
        try {  
            return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    @Override  
    public final int hashCode() {  
        try {  
            return ((Integer) super.h.invoke(this, m0, null)).intValue();  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    public final void request() {  
        try {  
            super.h.invoke(this, m3, null);  
            return;  
        } catch (Error e) {  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    @Override  
    public final String toString() {  
        try {  
            return (String) super.h.invoke(this, m2, null);  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
}  


        接着把获得的$Proxy0实例强制转换成Subject,并将引用赋给subject。当执行subject.request()方法时,就调用了$Proxy0类中的request()方法,进而调用父类Proxy中的h的invoke()方法.即InvocationHandler.invoke()。 

PS:一、须要说明的一点是,Proxy类中getProxyClass方法返回的是Proxy的Class类。之因此说明,是由于我一开始犯了个低级错误,觉得返回的是“被代理类的Class类”- -!推荐看一下getProxyClass的源码,很长=。= 
        二、从$Proxy0的源码能够看出,动态代理类不只代理了显示定义的接口中的方法,并且还代理了java的根类Object中的继承而来的equals()、hashcode()、toString()这三个方法,而且仅此三个方法。 

Q:到如今为止,还有一个疑问,invoke方法中的第一个参数是Proxy的实例(准确说,最终用到的是$Proxy0的实例),可是有什么用呢?或者说,程序内是怎样显示出做用的? 
A:就本人目前的水平看来,这个proxy参数并无什么做用,在整个动态代理机制中,并无用到InvocationHandler中invoke方法的proxy参数。而传入的这个参数实际是代理类的一个实例。我想多是为了让程序员在invoke方法中使用反射来获取关于代理类的一些信息吧。

 

 

如下的内容部分参考了网络上的内容,在此对原做者表示感谢! 

        Java中动态代理的实现,关键就是这两个东西:Proxy、InvocationHandler,下面从InvocationHandler接口中的invoke方法入手,简单说明一下Java如何实现动态代理的。 
        首先,invoke方法的完整形式以下: java

Java代码    收藏代码
  1. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable  
  2.     {  
  3.   
  4.         method.invoke(obj, args);  
  5.   
  6.         return null;  
  7.     }  


        首先猜想一下,method是调用的方法,即须要执行的方法;args是方法的参数;proxy,这个参数是什么?以上invoke()方法的实现便是比较标准的形式,咱们看到,这里并无用到proxy参数。查看JDK文档中Proxy的说明,以下: 程序员

Java代码    收藏代码
  1. A method invocation on a proxy instance through one of its proxy interfaces will be dispatched to the invoke method of the instance's invocation handler, passing the proxy instance,a java.lang.reflect.Method object identifying the method that was invoked, and an array of type Object containing the arguments.  


        由此能够知道以上的猜想是正确的,同时也知道,proxy参数传递的便是代理类的实例。 

        为了方便说明,这里写一个简单的例子来实现动态代理。 

       网络

Java代码    收藏代码
  1. //抽象角色(动态代理只能代理接口)  
  2. public interface Subject {  
  3.       
  4.     public void request();  
  5. }  

 

Java代码    收藏代码
  1. //真实角色:实现了Subject的request()方法  
  2. public class RealSubject implements Subject{  
  3.       
  4.     public void request(){  
  5.         System.out.println("From real subject.");  
  6.     }  
  7. }  

 

Java代码    收藏代码
  1. //实现了InvocationHandler  
  2. public class DynamicSubject implements InvocationHandler  
  3. {  
  4.     private Object obj;//这是动态代理的好处,被封装的对象是Object类型,接受任意类型的对象  
  5.   
  6.     public DynamicSubject()  
  7.     {  
  8.     }  
  9.   
  10.     public DynamicSubject(Object obj)  
  11.     {  
  12.         this.obj = obj;  
  13.     }  
  14.   
  15.     //这个方法不是咱们显示的去调用  
  16.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable  
  17.     {  
  18.         System.out.println("before calling " + method);  
  19.   
  20.         method.invoke(obj, args);  //----->这一步详看下一篇文章,java 经过反射机制调用某个类的方法,看完你会了解的。
  21.   
  22.         System.out.println("after calling " + method);  
  23.   
  24.         return null;  
  25.     }  
  26.   
  27. }  

 

Java代码    收藏代码
  1. //客户端:生成代理实例,并调用了request()方法  
  2. public class Client {  
  3.   
  4.     public static void main(String[] args) throws Throwable{  
  5.         // TODO Auto-generated method stub  
  6.   
  7.         Subject rs=new RealSubject();//这里指定被代理类  
  8.         InvocationHandler ds=new DynamicSubject(rs);  
  9.         Class<?> cls=rs.getClass();  
  10.           
  11.         //如下是一次性生成代理  
  12.           
  13.         Subject subject=(Subject) Proxy.newProxyInstance(  
  14.                 cls.getClassLoader(),cls.getInterfaces(), ds);  
  15.           
  16.         //这里能够经过运行结果证实subject是Proxy的一个实例,这个实例实现了Subject接口  
  17.         System.out.println(subject instanceof Proxy);  
  18.           
  19.         //这里能够看出subject的Class类是$Proxy0,这个$Proxy0类继承了Proxy,实现了Subject接口  
  20.         System.out.println("subject的Class类是:"+subject.getClass().toString());  
  21.           
  22.         System.out.print("subject中的属性有:");  
  23.           
  24.         Field[] field=subject.getClass().getDeclaredFields();  
  25.         for(Field f:field){  
  26.             System.out.print(f.getName()+", ");  
  27.         }  
  28.           
  29.         System.out.print("\n"+"subject中的方法有:");  
  30.           
  31.         Method[] method=subject.getClass().getDeclaredMethods();  
  32.           
  33.         for(Method m:method){  
  34.             System.out.print(m.getName()+", ");  
  35.         }  
  36.           
  37.         System.out.println("\n"+"subject的父类是:"+subject.getClass().getSuperclass());  
  38.           
  39.         System.out.print("\n"+"subject实现的接口是:");  
  40.           
  41.         Class<?>[] interfaces=subject.getClass().getInterfaces();  
  42.           
  43.         for(Class<?> i:interfaces){  
  44.             System.out.print(i.getName()+", ");  
  45.         }  
  46.   
  47.         System.out.println("\n\n"+"运行结果为:");  
  48.         subject.request();  
  49.     }  
  50. }  

 

Xml代码    收藏代码
  1. 运行结果以下:此处省略了包名,***代替  
  2. true  
  3. subject的Class类是:class $Proxy0  
  4. subject中的属性有:m1, m3, m0, m2,   
  5. subject中的方法有:request, hashCode, equals, toString,   
  6. subject的父类是:class java.lang.reflect.Proxy  
  7. subject实现的接口是:cn.edu.ustc.dynamicproxy.Subject,   
  8.   
  9. 运行结果为:  
  10. before calling public abstract void ***.Subject.request()  
  11. From real subject.  
  12. after calling public abstract void ***.Subject.request()  



PS:这个结果的信息很是重要,至少对我来讲。由于我在动态代理犯晕的根源就在于将上面的subject.request()理解错了,至少是被表面所迷惑,没有发现这个subject和Proxy之间的联系,一度纠结于最后调用的这个request()是怎么和invoke()联系上的,而invoke又是怎么知道request存在的。其实上面的true和class $Proxy0就能解决不少的疑问,再加上下面将要说的$Proxy0的源码,彻底能够解决动态代理的疑惑了。 

        从以上代码和结果能够看出,咱们并无显示的调用invoke()方法,可是这个方法确实执行了。下面就整个的过程进行分析一下: 

        从Client中的代码看,能够从newProxyInstance这个方法做为突破口,咱们先来看一下Proxy类中newProxyInstance方法的源代码: ide

Java代码    收藏代码
  1. public static Object newProxyInstance(ClassLoader loader,  
  2.         Class<?>[] interfaces,  
  3.         InvocationHandler h)  
  4. throws IllegalArgumentException  
  5. {  
  6.     if (h == null) {  
  7.         throw new NullPointerException();  
  8.     }  
  9.   
  10.     /* 
  11.      * Look up or generate the designated proxy class. 
  12.      */  
  13.     Class cl = getProxyClass(loader, interfaces);  
  14.   
  15.     /* 
  16.      * Invoke its constructor with the designated invocation handler. 
  17.      */  
  18.     try {  
  19.            /* 
  20.             * Proxy源码开始有这样的定义: 
  21.             * private final static Class[] constructorParams = { InvocationHandler.class }; 
  22.             * cons便是形参为InvocationHandler类型的构造方法 
  23.            */  
  24.         Constructor cons = cl.getConstructor(constructorParams);  
  25.         return (Object) cons.newInstance(new Object[] { h });  
  26.     } catch (NoSuchMethodException e) {  
  27.         throw new InternalError(e.toString());  
  28.     } catch (IllegalAccessException e) {  
  29.         throw new InternalError(e.toString());  
  30.     } catch (InstantiationException e) {  
  31.         throw new InternalError(e.toString());  
  32.     } catch (InvocationTargetException e) {  
  33.         throw new InternalError(e.toString());  
  34.     }  
  35. }  



        Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)作了如下几件事.
        (1)根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces)建立代理类$Proxy0.$Proxy0类 实现了interfaces的接口,并继承了Proxy类. 
        (2)实例化$Proxy0并在构造方法中把DynamicSubject传过去,接着$Proxy0调用父类Proxy的构造器,为h赋值,以下: this

Java代码    收藏代码
  1. class Proxy{  
  2.     InvocationHandler h=null;  
  3.     protected Proxy(InvocationHandler h) {  
  4.         this.h = h;  
  5.     }  
  6.     ...  
  7. }  



        来看一下这个继承了Proxy的$Proxy0的源代码: spa

Java代码    收藏代码
  1. public final class $Proxy0 extends Proxy implements Subject {  
  2.     private static Method m1;  
  3.     private static Method m0;  
  4.     private static Method m3;  
  5.     private static Method m2;  
  6.   
  7.     static {  
  8.         try {  
  9.             m1 = Class.forName("java.lang.Object").getMethod("equals",  
  10.                     new Class[] { Class.forName("java.lang.Object") });  
  11.   
  12.             m0 = Class.forName("java.lang.Object").getMethod("hashCode",  
  13.                     new Class[0]);  
  14.   
  15.             m3 = Class.forName("***.RealSubject").getMethod("request",  
  16.                     new Class[0]);  
  17.   
  18.             m2 = Class.forName("java.lang.Object").getMethod("toString",  
  19.                     new Class[0]);  
  20.   
  21.         } catch (NoSuchMethodException nosuchmethodexception) {  
  22.             throw new NoSuchMethodError(nosuchmethodexception.getMessage());  
  23.         } catch (ClassNotFoundException classnotfoundexception) {  
  24.             throw new NoClassDefFoundError(classnotfoundexception.getMessage());  
  25.         }  
  26.     } //static  
  27.   
  28.     public $Proxy0(InvocationHandler invocationhandler) {  
  29.         super(invocationhandler);  
  30.     }  
  31.   
  32.     @Override  
  33.     public final boolean equals(Object obj) {  
  34.         try {  
  35.             return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();  
  36.         } catch (Throwable throwable) {  
  37.             throw new UndeclaredThrowableException(throwable);  
  38.         }  
  39.     }  
  40.   
  41.     @Override  
  42.     public final int hashCode() {  
  43.         try {  
  44.             return ((Integer) super.h.invoke(this, m0, null)).intValue();  
  45.         } catch (Throwable throwable) {  
  46.             throw new UndeclaredThrowableException(throwable);  
  47.         }  
  48.     }  
  49.   
  50.     public final void request() {  
  51.         try {  
  52.             super.h.invoke(this, m3, null);  
  53.             return;  
  54.         } catch (Error e) {  
  55.         } catch (Throwable throwable) {  
  56.             throw new UndeclaredThrowableException(throwable);  
  57.         }  
  58.     }  
  59.   
  60.     @Override  
  61.     public final String toString() {  
  62.         try {  
  63.             return (String) super.h.invoke(this, m2, null);  
  64.         } catch (Throwable throwable) {  
  65.             throw new UndeclaredThrowableException(throwable);  
  66.         }  
  67.     }  
  68. }  



        接着把获得的$Proxy0实例强制转换成Subject,并将引用赋给subject。当执行subject.request()方法时,就调用了$Proxy0类中的request()方法,进而调用父类Proxy中的h的invoke()方法.即InvocationHandler.invoke()。 

PS:一、须要说明的一点是,Proxy类中getProxyClass方法返回的是Proxy的Class类。之因此说明,是由于我一开始犯了个低级错误,觉得返回的是“被代理类的Class类”- -!推荐看一下getProxyClass的源码,很长=。= 
        二、从$Proxy0的源码能够看出,动态代理类不只代理了显示定义的接口中的方法,并且还代理了java的根类Object中的继承而来的equals()、hashcode()、toString()这三个方法,而且仅此三个方法。 

Q:到如今为止,还有一个疑问,invoke方法中的第一个参数是Proxy的实例(准确说,最终用到的是$Proxy0的实例),可是有什么用呢?或者说,程序内是怎样显示出做用的? 
A:就本人目前的水平看来,这个proxy参数并无什么做用,在整个动态代理机制中,并无用到InvocationHandler中invoke方法的proxy参数。而传入的这个参数实际是代理类的一个实例。我想多是为了让程序员在invoke方法中使用反射来获取关于代理类的一些信息吧。代理