首页 > 编程语言 > 详细

java动态代理实现原理

时间:2020-01-13 13:46:17      阅读:65      评论:0      收藏:0      [点我收藏+]

代理模式分为静态代理和动态代理两种

1.静态代理:就是在编写代码的过程中由开发人员硬编码

public class Person{

   public void sleep(){
      System.out.println("我要睡觉了");  
   }    

}
public class Proxy{

    private Person p = new Person();
  
    public void preSleep() {
          doSomething();
          p.sleep();
    }
   }

代理对象始终维护了一个被代理对象的应用,当用户需要使用被代理对象时,使用代理对象而不直接使用被代理对象。这样就能实现在调用具体方法前后做出一些操作。

2.动态代理:代理类在程序运行时创建代理的方式成为动态代理

动态代理的创建需要使用到java.lang.reflect包下的Proxy类和InvocationHandler接口。

Proxy类有一个快速创建代理类对象的方法

Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

参数:

loader:需要传入一个类加载器,由这个ClassLoader对象来对生成的代理对象进行加载。
interfaces:接口数组,传入一个接口数组,代理对象会实现其中的接口,从而使代理对象能够调用其中的方法。
InvocationHandler :InvocationHandler对象,其中就是实现代理类所代理(增强)功能。传入此对象将会把代理对象和此handler关联到一起。

下面是具体的代码:

class ZCL implements dayLife{

    @Override
    public void BuyIce() {
        System.out.println("买个棒棒冰!");
    }

    @Override
    public String getMoney(String name) {
        System.out.println(name+"!钱交上来!");
        return "上交100块";
    }
    
}

 

ZCL zcl = new ZCL();//被代理的真实对象
               
dayLife proxy = (dayLife)Proxy.newProxyInstance(zcl.getClass().getClassLoader(), zcl.getClass().getInterfaces(),
     new InvocationHandler() {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("方法执行前:"+proxy.getClass()); Object invoke
= method.invoke(zcl, args); return args==null?invoke:args[0].toString()+invoke; } });//代理对象 proxy.BuyIce(); String money = proxy.getMoney("李华");
执行结果:
方法执行前:class com.sun.proxy.$Proxy0
买个棒棒冰!
方法执行前:class com.sun.proxy.$Proxy0
李华!钱交上来!
李华上交100块

InvocationHandler对象可以使用创建类的方式,我这里使用的是匿名类演示方便一点。

所以实质上动态代理的运行原理是将方法的执行委托给InvocationHandlerd对象的的invoke方法执行,InvocationHandler对象持有一个被代理对象的实例。
这样就可以在invoke方法中实现对代理方法的增强,而且不需要向静态代理那样每个方法都进行编码,因为生成的代理类中的方法执行都是通过InvocationHandler的invoke方法执行的,
所以只需要在invoke方法中进行方法的增强就可以了。

执行后打印的class名称为$Proxy0,是因为这是由jdk自动生成的名称,后面依次按0,1,2....

我们再来看一下jdk动态生成的字节码文件,因为是直接生成在内存当中的,我们可以使用一下方法保存到磁盘上。

byte[] generateProxyClass = ProxyGenerator.generateProxyClass(proxy.getClass().getSimpleName(),proxy.getClass().getInterfaces());
        try(FileOutputStream fileOutputStream = new FileOutputStream(new File("C:/Users/xxx/Desktop/$Proxy0.class"))){
            fileOutputStream.write(generateProxyClass);
            fileOutputStream.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }

然后再使用反编译软件进行查看,我这里使用的是JD。下面是代码

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import test.dayLife;

public final class $Proxy0 extends Proxy implements dayLife{
  private static Method m1;
  private static Method m3;
  private static Method m2;
  private static Method m4;
  private static Method m0;
  
  public $Proxy0(InvocationHandler paramInvocationHandler) throws {
    super(paramInvocationHandler);
  }
  
  public final boolean equals(Object paramObject)throws {
    try{
      return ((Boolean)this.h.invoke(this, m1, new Object[] {paramObject })).booleanValue();
    } catch (Error|RuntimeException localError){
      throw localError;
    }catch (Throwable localThrowable){
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final void BuyIce() throws {
    try{
      this.h.invoke(this, m3, null);
      return;
    } catch (Error|RuntimeException localError) {
      throw localError;
    }catch (Throwable localThrowable) {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String toString() throws {
    try{
      return (String)this.h.invoke(this, m2, null);
    }catch (Error|RuntimeException localError){
      throw localError;
    }catch (Throwable localThrowable){
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String getMoney(String paramString) throws  {
    try{
      return (String)this.h.invoke(this, m4, new Object[] { paramString });
    }catch (Error|RuntimeException localError){
      throw localError;
    }catch (Throwable localThrowable){
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final int hashCode()throws { 
    try {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    } catch (Error|RuntimeException localError){
      throw localError;
    } catch (Throwable localThrowable){
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  static{
    try{
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("test.dayLife").getMethod("BuyIce", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m4 = Class.forName("test.dayLife").getMethod("getMoney", new Class[] { Class.forName("java.lang.String") });
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }catch (NoSuchMethodException localNoSuchMethodException){
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }catch (ClassNotFoundException localClassNotFoundException){
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

最下面是静态代码块,首先会使用反射加接口的方法引用到成员变量,而构造函数是调用父类的构造函数,将InvocationHandler赋值给成员h,执行方法时使用InvocationHandler

的invoke方法去执行真正被代理对象的方法,这就是动态代理类的真面目。





 

java动态代理实现原理

原文:https://www.cnblogs.com/nubea/p/12186825.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!