文档章节

java 动态代理学习笔记

 漂泊的二货
发布于 2017/05/18 17:10
字数 1035
阅读 3
收藏 0

代理模式:代理模式就是对一个对象进行包装,包装生成的对象具有和原对象一样的方法列表,但是每个方法都进行了包装

 

静态代理

public interface MoveAble {
    
    public void run();
}

public class Car implements MoveAble {

    @Override
    public void run() {
        System.out.println("car is running");
    }

}

public class CarProxy implements MoveAble{
    
    private MoveAble target;

    public CarProxy(MoveAble target) {
        super();
        this.target = target;
    }

    @Override
    public void run() {
        this.target.run();
    }
    
    public static void main(String[] args) {
        CarProxy proxy = new CarProxy(new Car());
        proxy.run();
    }
    
}

    首先 我们定义了一个MoveAble接口,然后新建一个实现类,并且新建一个CarProxy代理类,CarProxy实现moveAble接口,同时在它内部定义一个变量MoveAble用来保存代理的实现类,这样代理类实现moveAble接口中的run方法时,其实调用的还是被代理类car中的run方法,同时 我们可以在代理类CarProxy中的run方法中添加 我们需要添加的逻辑,这样就完成了对car的代理。但是如果moveAble中添加方法时,代理类CarProxy也要增加相应的实现;如果不想这样的话,就得使用动态代理;

动态代理

下面我们征对上面的静态代理类 我们创建一个动态的代理类:

public class MoveAbleProxy implements InvocationHandler{
    
    private Object target;


    public MoveAbleProxy(Object target) {
        super();
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println(proxy.getClass().getSimpleName());
        method.invoke(target, args);
        return null;
    }
    
    public static void main(String[] args) {
        MoveAble car = new Car();
        //得到的moveProxy实现了MoveAble接口 继承了Proxy
    MoveAble moveProxy = (MoveAble)Proxy.newProxyInstance(car.getClass().getClassLoader(),         car.getClass().getInterfaces(), new MoveAbleProxy(car) ); 
        moveProxy.run();     
    }

}

这边与静态代理的区别在于 动态代理类实现的是InvocationHandler,与静态代理的main方法中测试代码比较会发现静态代理中我们是直接new CarProxy ,而在动态代理中我们是:

Proxy.newProxyInstance(car.getClass().getClassLoader(),         car.getClass().getInterfaces(), new MoveAbleProxy(car) ); 并将返回的对象强转成MoveAble。

所以动态代理的实现要一下几步:

(1)要定义一个接口,和一个该接口的实现类,这个实现类就是我们要代理的对象,代理其实就是在调用实现类方法时,在该方法的调用前后增加一个逻辑

(2)动态的代理类中必须要实现InvocationHandler接口,实现invoke方法。动态代理中生成的代理实例不会去直接调用实现类的方法,而是调用invoke方法。

(3)生成的代理里去调用实现类的方法时

MoveAble moveProxy = (MoveAble)Proxy.newProxyInstance(car.getClass().getClassLoader(),         car.getClass().getInterfaces(), new MoveAbleProxy(car) ); 

断点会发现moveProxy = $Proxy0 ,可以在main测试方法中添加

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");可以看一下该生成的代理类的源码:(moveProxy 其实是 实现了MoveAble接口 继承了Proxy)

public final class $Proxy0
  extends Proxy
  implements MoveAble
{
  private static Method m1;
  private static Method m3;
  private static Method m0;
  private static Method m2;
  
  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 run()
    throws 
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    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);
    }
  }
  
  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);
    }
  }
  
  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("com.myec.com.MoveAble").getMethod("run", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

在Proxy中的newProxyInstance的方法中:

   

 Class cl = getProxyClass(loader, interfaces);
    try {
        Constructor cons = cl.getConstructor(constructorParams);
        return (Object) cons.newInstance(new Object[] { h });
    } 

1这个生成了代理类的字节码,然后用参数里的classLoader加载这个代理类,生成$Proxy0实例

2.使用代理类父类的构造函数 Proxy(InvocationHandler h)来创造一个代理类的实例,将我们自定义的InvocationHandler(MoveAbleProxy )的子类传入。

3.返回这个代理类实例,因为我们构造的代理类实现了interfaces(也就是我们程序中传入的car.getClass().getInterfaces())里的所有接口,因此返回的代理类可以强转成MoveAble类型来调用接口中定义的方法。

 

 

 

 

 

 

© 著作权归作者所有

共有 人打赏支持
粉丝 0
博文 2
码字总数 1138
作品 0
浦东
111 多线程JUC包下代码分析

Java多线程系列目录(共43篇) AtomicLongFieldUpdater:通过反射+CAS实现对传入对象的指定long字段实现类似AtomicLong的操作 http://www.cnblogs.com/skywang12345/p/javathreadscategory.ht...

素雷
2017/10/31
0
0
动态代理机制详解(JDK 和CGLIB,Javassist,ASM)

在运行时期可以按照Java虚拟机规范对class文件的组织规则生成对应的二进制字节码。当前有很多开源框架可以完成这些功能,如ASM,Javassist。 动态代理机制详解(JDK 和CGLIB,Javassist,ASM...

素雷
2017/10/19
0
0
java提供类与cglib包实现动态代理

终于有点空余时间,决定把之前学习的知识点整理一下,备以后复习。 动态代理有三角色:抽象角色,代理角色,真是角色。 第一个记录下java提供的动态代理。即使用Proxy类和InvocationHandel接...

kyle1970
2012/11/22
0
0
Hadoop权威指南阅读笔记(三)

hadoop的序列化机制与java的序列化机制不同,他将对象序列化到流中,值得一提的是java的序列化机制是不断的创建对象,但在Hadoop的序列化机制中,用户可以服用对象这样就减少了java对象的分配...

蓝狐乐队
2014/04/27
0
0
【目录导航】JAVA零基础进阶之路

【JAVA零基础入门系列】(已完结)导航目录 Day1 开发环境搭建 Day2 Java集成开发环境IDEA Day3 Java基本数据类型 Day4 变量与常量 Day5 Java中的运算符 Day6 Java字符串 Day7 Java输入与输出...

MFrank
06/21
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Ubuntu18.04 显卡GF-940MX安装NVIDIA-390.77

解决办法: 下面就给大家一个正确的姿势在Ubuntu上安装Nvidia驱动: (a)首先去N卡官网下载自己显卡对应的驱动:www.geforce.cn/drivers (b)下载后好放在英文路径的目录下,怎么简单怎么来...

AI_SKI
今天
0
0
深夜胡思乱想

魔兽世界 最近魔兽世界出了新版本, 周末两天升到了满级,比之前的版本体验好很多,做任务不用抢怪了,不用组队打怪也是共享拾取的。技能简化了很多,哪个亮按哪个。 运维 服务器 产品 之间的...

Firxiao
今天
0
0
MySQL 8 在 Windows 下安装及使用

MySQL 8 带来了全新的体验,比如支持 NoSQL、JSON 等,拥有比 MySQL 5.7 两倍以上的性能提升。本文讲解如何在 Windows 下安装 MySQL 8,以及基本的 MySQL 用法。 下载 下载地址 https://dev....

waylau
今天
0
0
微信第三方平台 access_token is invalid or not latest

微信第三方开发平台code换session_key说的特别容易,但是我一使用就带来无穷无尽的烦恼,搞了一整天也无济于事. 现在记录一下解决问题的过程,方便后来人参考. 我遇到的这个问题搜索了整个网络也...

自由的开源
今天
2
0
openJDK之sun.misc.Unsafe类CAS底层实现

注:这篇文章参考了https://www.cnblogs.com/snowater/p/8303698.html 1.sun.misc.Unsafe中CAS方法 在sun.misc.Unsafe中CAS方法如下: compareAndSwapObject(java.lang.Object arg0, long a......

汉斯-冯-拉特
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部