JDK动态代理案例与原理分析

一、JDK动态代理实现案例

Person接口

package com.zhoucong.proxy.jdk;

public interface Person {

//    寻找真爱
    void findlove();
    
}

人物实现类

package com.zhoucong.proxy.jdk;

public class Zhangsan implements Person{
    
    @Override
    public void findlove() {
        System.out.println("我叫张三,性别女,我找对象的要求如下:\n");
        System.out.println("高富帅");
        System.out.println("有房有车");
        System.out.println("身高180cm以上,体重70kg");
    }

}

代理类

package com.zhoucong.proxy.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MeiPo implements InvocationHandler{

    private Person target;
    
//  获取被代理人的个人资料
    public Object getInstance(Person target) throws Exception {
        this.target = target;
        Class clazz = target.getClass();
        System.out.println("被代理对象的class是:"+ clazz);
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
        
    }
    
    
 @Override
    public Object invoke(Object arg0, Method method, Object[] args) throws Throwable {
     System.out.println("我是媒婆!!");
     System.out.println("开始信息海选...");
     System.out.println("-------------");
     
     method.invoke(this.target, args);
     System.out.println("-------------");
     System.out.println("如果合适的话,就准备办事");
     return null;
    }

}

运行测试

package com.zhoucong.proxy.jdk;
public class TestFindLove {

    public static void main(String[] args) {

        try {
            Person obj = (Person) new MeiPo().getInstance(new Zhangsan());
            System.out.println(obj.getClass());
            obj.findlove();

            /**
             * 原理: 
             * 1.拿到被代理对象的引用,然后获取它的接口
             * 2.jdk代理重新生成一个类,同时实现我们个额的代理对象所实现的接口
             * 3.把被代理对象的引用也拿到了
             * 4.重新动态生成一个class字节码
             * 5.然后编译
             */


        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

运行结果:

重点:

代理前对象为  com.zhoucong.proxy.jdk.Zhangsan

代理后获得的对象  com.sun.proxy.$Proxy0

二、原理分析

获取$Proxy0.class字节码内容

package com.zhoucong.proxy.jdk;

import java.io.FileOutputStream;
import sun.misc.ProxyGenerator;


public class TestFindLove {

    public static void main(String[] args) {

        try {
            Person obj = (Person) new MeiPo().getInstance(new Zhangsan());
            System.out.println(obj.getClass());
            obj.findlove();

            
//            获取字节码内容
//            ProxyGenerator需要导入jdk安装目录jre/bin下的rt.jar

            byte[] generateProxyClass = ProxyGenerator.generateProxyClass("$Proxy0", new Class[] { Person.class });
//            输出到本地
            FileOutputStream os = new FileOutputStream("E:/GP_WORKSPACE/$Proxy0.class");
            os.write(generateProxyClass);
            os.close();

    
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

利用反编译工具得到Java文件如下:

$Proxy0.java

import com.zhoucong.proxy.jdk.Person;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Person {
  private static Method m1;
  
  private static Method m2;
  
  private static Method m0;
  
  private static Method m3;
  
  public $Proxy0(InvocationHandler paramInvocationHandler) {
    super(paramInvocationHandler);
  }
  
  public final boolean equals(Object paramObject) {
    try {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }
  
  public final String toString() {
    try {
      return (String)this.h.invoke(this, m2, null);
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }
  
  public final int hashCode() {
    try {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }
  
  public final void findlove() {
    try {
      this.h.invoke(this, m3, null);
      return;
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }
  
  static {
    try {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m3 = Class.forName("com.zhoucong.proxy.jdk.Person").getMethod("findlove", new Class[0]);
      return;
    } catch (NoSuchMethodException noSuchMethodException) {
      throw new NoSuchMethodError(noSuchMethodException.getMessage());
    } catch (ClassNotFoundException classNotFoundException) {
      throw new NoClassDefFoundError(classNotFoundException.getMessage());
    } 
  }
}

要点分析:

特点:1、JDK代理生成的类实现了Person接口继承父类Proxy

    分析:JDK实现动态代理必须要有接口(cglib没有)

   2、静态代码块获取了接口中的方法

m3 = Class.forName("com.zhoucong.proxy.jdk.Person").getMethod("findlove", new Class[0]);

   3、JDK代理生成的类实现了接口方法,里面写了重要的一句话

 this.h.invoke(this, m3, null);

分析:this.h 去父类Proxy中查看得知为父类的成员变量

/**
     * the invocation handler for this proxy instance.
     * @serial
     */
    protected InvocationHandler h;

即MeiPo类并且调用了里面的Object invoke(Object arg0, Method method, Object[] args)方法

 @Override
    public Object invoke(Object arg0, Method method, Object[] args) throws Throwable {
     System.out.println("我是媒婆!!");
     System.out.println("开始信息海选...");
     System.out.println("-------------");
    // this.target.findlove();  //还可以写成如下,效果一样
  // 利用反射机制实现
method.invoke(this.target, args); System.out.println("-------------"); System.out.println("如果合适的话,就准备办事"); return null; }

猜你喜欢

转载自www.cnblogs.com/itzhoucong/p/12143704.html