文档章节

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
浦东
咕泡-代理 proxy 设计模式笔记

##查看代码:https://gitee.com/jly521/proxy.git 代理模式(Proxy) 应用场景:为其他对象提供一种代理以控制对这个对象的访问 从结构上来看和Decorator 模式类似, 但Proxy 是控制,更像是...

职业搬砖20年
08/22
0
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

没有更多内容

加载失败,请刷新页面

加载更多

Snackbar源码分析

目录介绍 1.最简单创造方法 1.1 Snackbar作用 1.2 最简单的创建 1.3 Snackbar消失的几种方式 2.源码分析 2.1 Snackbar的make方法源码分析 2.2 对Snackbar属性进行设置 2.3 Snackbar的show显示...

潇湘剑雨
35分钟前
1
0
分布式作业系统 Elastic-Job-Lite 源码分析 —— 作业数据存储

分布式作业系统 Elastic-Job-Lite 源码分析 —— 作业数据存储 摘要: 原创出处 http://www.iocoder.cn/Elastic-Job/job-storage/ 本文基于 Elastic-Job V2.1.5 版本分享 1. 概述 本文主要分享...

DemonsI
42分钟前
1
0
jmockit demo

1、@Mocked,标识一个指定的class的实例或被测对象的参数被Mock掉。 2、@Capturing,标识一个被Mock的对象,从该对象派生的子类也被Mock了。 3、@Injectable,标识只有一个指定的被测对象的内...

我的老腰啊
56分钟前
1
0
内容换行

用 <textarea>13611112222 这里想换行 13877779999</textarea><textarea>13611112222 13877779999</textarea>...

小黄狗
57分钟前
1
0
学习设计模式——单例模式

1. 认识单例模式 1. 定义:一个类中仅有一个实例,并提供一个访问它的全局访问点。 2. 结构:仅一个Singleton类,其中包含一个static类变量,而类变量的类型就是Singleton类,而且Singleton...

江左煤郎
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部