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. 转载:Struts2支持断点续传下载实现

    转自:http://blog.sina.com.cn/s/blog_667ac0360102eckm.html package com.ipan.core.controller.web.result; ...

  2. Ubuntu16.04 Tomcat9的安装

    1. 从http://tomcat.apache.org/download-90.cgi 下载apache-tomcat-9.0.0.M11.tar.gz 2. 上传到Linux后移动到/opt/to ...

  3. ACM计算几何模板——圆和球

    #include <iostream> #include <cmath> using namespace std; #define eps 1e-10 /********** ...

  4. C#正则表达式操作中使用LINQ

    比如:[程序员][代码]博客园 - 程序员的网上家园,代码改变世界 提取出来的Tag应该是:[程序员].[代码] Regex _regexTag = new Regex(@"^(\[[^\] ...

  5. K-mean聚类算法汇聚有用信息——学习笔记

    无监督-无标签 聚类,难点在于评估和调参. k-means最简单实用 基本概念 K值:数据聚成多少类. 质心:各个维度算平均数.Centroid 相似度量:距离来算(欧式距离——直线距离,余弦距离) ...

  6. VC中的学习点滴

    1.  __stdcall 和 __cdecl __cdecl 是C Declaration的缩写(declaration,声明),表示C语言默认的函数调用方法:所有参数从右到左依次入栈,由调用者负责 ...

  7. 【BZOJ1135】[POI2009]Lyz 线段树

    [BZOJ1135][POI2009]Lyz Description 初始时滑冰俱乐部有1到n号的溜冰鞋各k双.已知x号脚的人可以穿x到x+d的溜冰鞋. 有m次操作,每次包含两个数ri,xi代表来了x ...

  8. 【BZOJ4002】[JLOI2015]有意义的字符串 数学

    [BZOJ4002][JLOI2015]有意义的字符串 Description B 君有两个好朋友,他们叫宁宁和冉冉.有一天,冉冉遇到了一个有趣的题目:输入 b;d;n,求 Input 一行三个整数 ...

  9. Android 全局异常处理(三)

    用过安卓手机的用户以及安卓开发者们会时长碰到程序异常退出的情况,普通用户遇到这种情况,肯定非常恼火,甚至会骂一生垃圾软件,然后卸载掉.那么开发者们在开发过程中遇到这种情况给怎么办呢,当然,你不可能世界 ...

  10. 逐一取Map值

    String[] mKeys = starDetil.getRows().keySet().toArray(new String[starDetil.getRows().size()]); starD ...