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. node.js之web开发 koa入门

    用Node.js开发Web服务器端,有几个显著的优势: 速度快,非常快!这得益于Node.js天生是异步的. 常见的Web框架包括:Express,Sails.js,koa,Meteor,DerbyJ ...

  2. hdu 2612:Find a way(经典BFS广搜题)

    Find a way Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  3. 运动目标检测ViBe算法

    一.运动目标检测简介   视频中的运动目标检测这一块现在的方法实在是太多了.运动目标检测的算法依照目标与摄像机之间的关系可以分为静态背景下运动检测和动态背景下运动检测.先简单从视频中的背景类型来讨论. ...

  4. hdu 1513(dp+滚动数组)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1513 思路:n这么大,可以采用滚动数组,然后就是求原串和反串的LCS了. #include<io ...

  5. hdu 4715(打表)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4715 思路:先打个素数表,然后判断一下就可以了. #include<iostream> # ...

  6. Eclipse中如何clean项目以及clean的作用

    http://blog.csdn.net/vipmao/article/details/51228171

  7. Python3x 爬取妹子图

    思路:1.get_totalpages(url)  通过[性.感.美.女.图]获得该版块的总页数 [首页1234567891011下一页末页共 21页1034条] 2.get_sercoverurl( ...

  8. ios开发之 --调用系统的页面,显示中文

    在开发的过程中,我们会接入很多的sdk,比如相机,相册,是否允许获取位置等,大多数的情况下是默认显示英文, 在plist文件里面添加一个key就可以了,如下图: key:Localization na ...

  9. studio导入Eclipse 项目要改的文件

    添加下面文件即可,一个不能少 1. project 2.project.properties 3.classpath 4.AndroidManifest.xml 以上目录都有可以正常导入studio中

  10. 使用pug(jade),以及在vue+webpack中使用pug(jade)

    一:在HTML中使用pug 在css中有预处理器less和scss来使我们的样式表更加的简介,那么在HTML中有没有这样的格式呢,答案是有的,那就是pug(前身是jade),效果如下: 转译以后 好, ...