java动态代理是java语言的一项高级特性。在平时的项目开发中,可能很难遇到动态代理的案例。但是动态代理在很多框架中起着不可替代的作用,例如Spring的AOP。今天我们就聊一聊java动态代理的实现原理。

jdk对于动态代理的支持主要依赖于两个类:Proxy和InvocationHandler。我们先看一下类图。

  Subject类是主题类,定义了我要做什么。我们需要代理的类即实现Subject接口的RealSubject。

  1.InvocationHandler

  InvocationHandler接口是jdk提供的接口,这个接口只有一个方法

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

我们先了解下InvocationHandler这个类是做什么。以下是java doc

* <p>Each proxy instance has an associated invocation handler.
* When a method is invoked on a proxy instance, the method
* invocation is encoded and dispatched to the {@code invoke}
* method of its invocation handler.

  每一个代理实例都会和一个invocation handler关联,准确的说,每一个proxy类都会持有一个InvocationHandler实例,并且将目标函数交给InvcationHandler实例去执行。InvocationHandler只有invoke()这个方法,这个方法即实际被调用的方法。不管代理调用的是何种方法,处理器被调用的一定是invoke()方法。下面我们看看这个方法的参数。

  1. Object proxy。传入的Subject引用,即我们想要真正执行的目标对象。

  2. Method method。Method是java reflection API的一部分。这里传入的method对象,是实际被调用的method方法。

  3. Object[] args。这是方法调用时传入的参数数组。

  了解invoke()方法后,读者一定想知道,Subject的目标方法是怎么被调用的呢?接下来我们继续了解Proxy类。

  2. Proxy

  接下来我们了解下Proxy类是如何与InvocationHandler一共工作的。java doc中对Proxy的介绍如下:

* provides static methods for creating dynamic proxy
* classes and instances, and it is also the superclass of all
* dynamic proxy classes created by those methods.

  Proxy提供了一个静态方法去创建动态代理类,最常用的就是下面这个方法了。

 public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)

  利用newProxyInstance可以动态的创建所需要的代理对象,并且和与它关联的InvocationHandler绑定。参数如下

  1. ClassLoader loader, 加载代理类的类加载器。

  2. Class<?>[] interfaces, 代理类实现的接口。创建的代理类对象,只能强转为该interfaces的子类。

  3. InvocationHandler h, 代理类所关联的InvocationHandler。所有被代理的方法都会通过该InvocationHandler的invoke()方法执行。

  newProxyInstance方法是生成代理类的关键方法,代理类在程序运行的过程中生成,因而叫做动态代理。

  3. 案例

  了解了这两个最重要的类之后,我们需要通过一个实例来帮助我们更好的理解动态代理的运行机制。

  首先我们创建一个Subject接口以及其实现类。

  步骤1. 定义Subject

 public interface Subject {

     public void say(String str);
} public class SubjectBean implements Subject { @Override
public void say(String str) {
System.out.println(str);
}
}

  Subject的say方法是我们需要代理的方法。在该方法的前后我们不妨做一些额外的操作。接下来我们定义我们的InvocationHandler。

  步骤2. 定义InvocationHandler

 public class MyInvocationHandle implements InvocationHandler {

     Subject subject;

     public MyInvocationHandle(Subject subject) {
this.subject = subject;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("pre");
method.invoke(subject, args);
System.out.println("post");
return null;
} }

  通过构造器,把被代理的对象传入。

  步骤3. 定义生成代理类方法实现

public class Main {

    public static Subject getProxy(Subject subject){
return (Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(),
subject.getClass().getInterfaces(),
new MyInvocationHandle(subject));
} public static void main(String[] args) {
Subject subject = new SubjectBean();
Subject proxy = getProxy(subject);
proxy.say("hello");
}
}

  执行main函数,最后输出的结果为:

 可见,say()函数真正method.invoke(subject, args)这里完成的。在执行前后可以加入任意代码片段,完成对say()方法的增强操作。

 4. debug

  我们对main方法debug看看,proxy类到底是什么。如下图

  

  com.sun.proxy.$Proxy()类,是Proxy.newProxyInstance被调用后在jvm运行时动态生成的一个对象,命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号。至于它为什么可以转为Subject,是因为我们在传入的第二个参数中,规定了它的类型信息。

  这篇文章主要简述了java动态代理的实现机制。如有错误之处,还望读者多多指教。

  参考文献:

 《Head First设计模式》

作者:mayday芋头
本博客中未标明转载的文章归作者mayday芋头和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

理解java动态代理的更多相关文章

  1. 深入理解 Java 动态代理机制

    Java 有两种代理方式,一种是静态代理,另一种是动态代理.对于静态代理,其实就是通过依赖注入,对对象进行封装,不让外部知道实现的细节.很多 API 就是通过这种形式来封装的. 代理模式结构图(图片来 ...

  2. 彻底理解JAVA动态代理

    代理设计模式 定义:为其他对象提供一种代理以控制对这个对象的访问. 代理模式的结构如下图所示. 动态代理使用 java动态代理机制以巧妙的方式实现了代理模式的设计理念. 代理模式示例代码 public ...

  3. 理解Java动态代理(1)—找我还钱?我出钱要你的命

    代理模式是最常用的一个设计模式之一,理解起来也是很简单,一张图足以说明了,LZ就不废话了. 至于代理模式能干嘛也不是LZ今天想说的,今天主要想简单介绍下JAVA里面的动态代理.“动”当然是相对“静”来 ...

  4. 深入理解java动态代理机制

    动态代理其实就是java.lang.reflect.Proxy类动态的根据您指定的所有接口生成一个class byte,该class会继承Proxy类,并实现所有你指定的接口(您在参数中传入的接口数组 ...

  5. 轻松理解 Java 静态代理/动态代理

    目录 什么是代理模式 定义 代理模式的主要角色 优点 缺点 静态代理 动态代理 JDK原生动态代理 例子 分析 小结 CGLIB动态代理 例子 分析 final类型 其他方案 尾声 理解Java动态代 ...

  6. JAVA动态代理基础

    Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM) 彻底理解JAVA动态代理 class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中. ...

  7. 详解java动态代理机制以及使用场景

    详解java动态代理机制以及使用场景 https://blog.csdn.net/u011784767/article/details/78281384 深入理解java动态代理的实现机制 https ...

  8. JAVA动态代理的全面深层理解

    Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过 ...

  9. JAVA动态代理模式(从现实生活角度理解代码原理)

    所谓动态代理,即通过代理类:Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联. java动态代理主要是使用java.lang.reflect包中的两个 ...

随机推荐

  1. 【BZOJ】1029: [JSOI2007]建筑抢修(贪心)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1029 按右端点排序后依次加入,并且每一次看是否能被修筑,如果能就修:否则查找原来修过的,如果原来修过 ...

  2. 【noip模拟题】最大公约数(数论)

    好神的一题... 首先我们只需要枚举这个gcd即可..从大到小,然后问题转换为判定问题...即判定是否有k个数有gcd这个约数.. orz 这样做的复杂度最坏是O(n+n/2+n/3+…+n/n)=O ...

  3. ERROR getting 'android:label' attribute: attribute is not a string value

    这个的原因很多地方都有描述,原因多半是多国语言string.xml 有的有这个值, 有的没有. 关键是怎么定位? 实际上他报错的是当前处理的xml element有问题, 而出错的时候盖住了要处理的. ...

  4. Unity中用触摸控制物体旋转和放大

    using UnityEngine;using System.Collections;using System.IO; public class ScaleAndRotate : MonoBehavi ...

  5. CPU GPU设计工作原理《转》

    我知道这非常长,可是,我坚持看完了.希望有幸看到这文章并对图形方面有兴趣的朋友,也能坚持看完.一定大有收获.毕竟知道它们究竟是怎么"私下勾搭"的.会有利于我们用程序来指挥它们... ...

  6. 应用开发之WinForm环境

    本章简言 上一章笔者讲到关于IO文件操作类,了解如何处理文件流.从这一章开始笔者将讲解相对比较高级的知识点.而本章笔者就对WinForm开发的知识点进行讲解和引导.现在很多业务都是面向于B/S模式的开 ...

  7. 调用PostgreSQL存储过程,找不到函数名的问题

    PostgreSQL的表,函数名称都是严格区分大小写的,所以在使用的时候没有注意大小写问题容易导致找不到函数名的错误,但最近两天我们发现,如果函数参数使用了自定义的数据类型,也会发生这个问题. 问题描 ...

  8. 自定义控件_StickyNavLaout

    关注我一.View结构原理1.extends linearLayout 继承想要用的布局,首先完成布局的填充在 onFinishInflate 方法中 findViewById(); @Overrid ...

  9. android how to deal with data when listview refresh

    如何解决listview数据刷新,下拉刷新,上拉加载更多时,图片不闪烁. 在Activity的onResume()方法中将adaper和listView重新再绑定一次. listView.setAda ...

  10. Linux下查看nginx的安装路径

    输入:nginx -V 输出:configure arguments: --prefix=/usr/local/nginx