JDK动态代理的一个实验与分析

package com.ssm.jdkproxy;

public interface Hello {
    public void sayHello();
    public String add(int a,int b);
}
package com.ssm.jdkproxy;

public class HelloImp1 implements Hello {


    public  HelloImp1(){

    }
    public  HelloImp1(int i){
        System.out.println(i);
    }
    @Override
    public void sayHello() {
        System.out.println("执行了sayHello方法");
    }
    public String add(int a,int b){
        int c=a+b;
        System.out.println("执行了add方法"+c);
        return ("执行了add方法"+c);
    }
    public void hey(){
        System.out.println("hey");
    }
}
package com.ssm.jdkproxy;

import java.lang.reflect.*;
import java.util.logging.Filter;

public class JdkProxyExample implements InvocationHandler {
    private Object target = null;


    public Object bind(Object target){
        this.target= target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),this);

    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理对象所属的类"+proxy.getClass());
        System.out.println("传进来的方法"+method.toString());
        System.out.println("参数列表"+(args!=null?args:"没有参数"));
        System.out.println("调度真实对象之前");
        Object obj = method.invoke(target,args);
        System.out.println("调度真实对象结束");
        System.out.println();
        return obj;
    }

    public static void main(String[] args) {
        JdkProxyExample jdk = new JdkProxyExample();
        Hello proxy = (Hello)jdk.bind(new HelloImp1());
        System.out.println(proxy.getClass());
        Class c = proxy.getClass();

        Class[] inter = c.getInterfaces();
        System.out.println("------------------"+"实现的接口-----------------------");
        for (Class aIn:inter
        ) {
            System.out.println(aIn);
        }
        System.out.println();

        System.out.println("------------------"+c+"的所有构造器-----------------------");
        Constructor[] con = c.getConstructors();
        for (Constructor aCon:con
             ) {
            System.out.println(aCon);
        }
        System.out.println();

        System.out.println("------------------"+c+"的所有字段----------------------");
        Field[] fields = c.getDeclaredFields();
        for (Field f: fields
        ) {
            System.out.println(f);
        }
        System.out.println();

        System.out.println("------------------"+c+"的所有方法----------------------");
        Method[] methods = c.getDeclaredMethods();
        for (Method method:methods
        ) {
            System.out.println(method);

        }
        System.out.println();


        System.out.println("-------------"+"反射创建代理类对象并调用方法"+"-----------");
        try {
            Object aProxy = con[0].newInstance(jdk);
            System.out.println(aProxy.equals(proxy));
            Method aMeth = aProxy.getClass().getDeclaredMethod("add",int.class,int.class);
            aMeth.invoke(aProxy,1,2);
        } catch (Exception e) {
            e.printStackTrace();
        }


        proxy.add(1,2);
    }
}

程序的执行结果:

class com.sun.proxy.$Proxy0
实现的接口
interface com.ssm.jdkproxy.Hello

class com.sun.proxy.$Proxy0的所有构造器:
public com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)

class com.sun.proxy.$Proxy0的所有函数:
public final java.lang.String com.sun.proxy.$Proxy0.add(int,int)
public final boolean com.sun.proxy.$Proxy0.equals(java.lang.Object)
public final java.lang.String com.sun.proxy.$Proxy0.toString()
public final int com.sun.proxy.$Proxy0.hashCode()
public final void com.sun.proxy.$Proxy0.sayHello()

反射执行add方法
代理对象所属的类class com.sun.proxy.$Proxy0
传进来的方法public abstract java.lang.String com.ssm.jdkproxy.Hello.add(int,int)
参数列表[Ljava.lang.Object;@4b67cf4d
调度真实对象之前
3
调度真实对象结束

代理对象所属的类class com.sun.proxy.$Proxy0
传进来的方法public abstract java.lang.String com.ssm.jdkproxy.Hello.add(int,int)
参数列表[Ljava.lang.Object;@7ea987ac
调度真实对象之前
3
调度真实对象结束

    首先可以看出一点:JDK动态代理虽然是对对象的代理,但是同时生成了代理类,代理类的Class文件存放在com.sun.proxy包之下.也就是说

Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),this);

这个语句首先生成了一个Class文件,新建了一个类,然后返回了一个类的实例.    

    我们再来看一下这个类都定义了那些东西,通过反射查看这个com.sun.proxy.$Proxy0类

实现的接口

interface com.ssm.jdkproxy.Hello

通过反射我们查看到这个类只实现了一个接口也就是与被代理的实际对象所实现的接口,这也是为什么JDK动态代理一个对象的时候,其所属的类必须实现接口.

构造器

可以看到,不管真实类有多少构造器,代理类只有一个构造器:

public com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)

这个构造器只有一个参数,就是一个实现了InvocationHandler接口的对象.

结合一下前面的内容我们现在大概知道newProxyInstance方法做了什么事情了.

Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),this);

这个方法首先通过传入的类加载器和相应的接口信息生成了一个类,然后通过第三个参数作为构造器的参数传递给了com.sun.proxy.$Proxy0的构造器,生成了一个com.sun.proxy.$Proxy0类的对象.

上面的过程是newProxyInstance函数自动执行的. 我们现在已经得到com.sun.proxy.$Proxy0的构造器了,我们手动来调用一下这个构造器.

        try {
            Object aProxy = con[0].newInstance(jdk);
            System.out.println(aProxy.equals(proxy));
            Method aMeth = aProxy.getClass().getDeclaredMethod("add",int.class,int.class);
            aMeth.invoke(aProxy,1,2);
        } catch (Exception e) {
            e.printStackTrace();
        }

输出结果:

false
代理对象所属的类class com.sun.proxy.$Proxy0
传进来的方法public abstract java.lang.String com.ssm.jdkproxy.Hello.add(int,int)
参数列表[Ljava.lang.Object;@7ea987ac
调度真实对象之前
3
调度真实对象结束

这个结果和直接使用newProxyInstance方法生成的对象具有同样的效果,这也验证了我们之前的猜想.newProxyInstance先创建了一个类,然后使用当前对象作为构造器参数构造了一个代理对象.

有一点需要注意一下,看一下getDeclaredMethods()的结果显示有equals()方法,说明代理类重写了equals方法. 但是我们这一句System.out.println(aProxy.equals(proxy))的执行结果是false,也就是谁虽然看起来我们是使用相同的JdkProxyExample对象来作为构造器参数构造代理对象,但是产生的对象还是不同的.因为没有去找com.sun.proxy.$Proxy0的class文件进行反编译,所以也不知道具体原因是什么.

拥有的字段

private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m1
private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m4
private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m2
private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m3
private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m0

可以看出代理类拥有五个实例变量,而且都是静态Method变量,刚好对应代理类中的五个方法.但实际存放的是实际对象的Method. 在使用代理调用方法是作为真实的函数传递给invoke函数.

实现的方法

class com.sun.proxy.$Proxy0的所有函数:
public final java.lang.String com.sun.proxy.$Proxy0.add(int,int)
public final boolean com.sun.proxy.$Proxy0.equals(java.lang.Object)
public final java.lang.String com.sun.proxy.$Proxy0.toString()
public final int com.sun.proxy.$Proxy0.hashCode()
public final void com.sun.proxy.$Proxy0.sayHello()

主要看两个方法,也就是我们在接口中定义的方法add和sayHello.这两个方法都被代理类所实现了.然后再看一下HelloImp1中定义的方法hey()在代理类中并没有被实现. 所以我们可以得到结论,JDK动态代理只会实现接口中所定义的方法,而不是实现代理类的所有方法.

直接使用proxy执行方法

代理对象所属的类class com.sun.proxy.$Proxy0
传进来的方法public abstract java.lang.String com.ssm.jdkproxy.Hello.add(int,int)
参数列表[Ljava.lang.Object;@12a3a380
调度真实对象之前
执行了add方法3
调度真实对象结束

可以看到,调用代理类的方法执行了invoke函数.那我们应该很容易想到,代理类方法的实现其实只是在调用invoke函数(就是我们作为构造器参数的那个对象所属类中的invoke函数).

invoke函数

我们继续看一下invoke函数.

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

的参数,一个proxy,一个method对象,一个参数列表.

这里就很好理解了,我们在为代理类传了一个JdkProxyExample的对象作为参数,在代理类的方法实现中使用这个对象来调用其invoke方法,传的三个参数分别是,当前proxy对象,对proxy对象调用的method,调用方法传入的参数列表. 我们可以通过代码来验证一下这个猜想,具体代码就不放上来了.

 

总结

所以我们来总结一下,JDK动态代理.

首先我们要使用JDK动态代理首先要有一个实现接口的类,然后一个实现InvocationHandler接口的代理逻辑实现类.代理逻辑的实现类当中要有一个public Object invoke(Object proxy, Method method, Object[] args)方法.

我们可以通过

Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),InvocationHandler handler)

来创建一个代理类的实例,该方法有三个参数: (真实类的类加载器,真实类实现的接口的Class对象列表,实现了InvocationHandler接口的类的实例对象),前面两个参数的作用是,使用这两个信息来构造一个代理类的Class文件并进行加载(也就是说动态代理实际上创建了新的加载到方法区的类),最后一个参数的作用是 对代理类的函数调用将通过发送给这个对象的invoke函数来实现.

 

最后放一个$Proxy0的源码(不是本例的):

//$proxy0的源码
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("接口的实现类的路径").getMethod("实现类的方法",  
                    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 接口的实现类的方法() {  
        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);  
        }  
    }  
}

 

 

你可能感兴趣的:(java)