理解java动态代理
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设计模式》
理解java动态代理的更多相关文章
- 深入理解 Java 动态代理机制
Java 有两种代理方式,一种是静态代理,另一种是动态代理.对于静态代理,其实就是通过依赖注入,对对象进行封装,不让外部知道实现的细节.很多 API 就是通过这种形式来封装的. 代理模式结构图(图片来 ...
- 彻底理解JAVA动态代理
代理设计模式 定义:为其他对象提供一种代理以控制对这个对象的访问. 代理模式的结构如下图所示. 动态代理使用 java动态代理机制以巧妙的方式实现了代理模式的设计理念. 代理模式示例代码 public ...
- 理解Java动态代理(1)—找我还钱?我出钱要你的命
代理模式是最常用的一个设计模式之一,理解起来也是很简单,一张图足以说明了,LZ就不废话了. 至于代理模式能干嘛也不是LZ今天想说的,今天主要想简单介绍下JAVA里面的动态代理.“动”当然是相对“静”来 ...
- 深入理解java动态代理机制
动态代理其实就是java.lang.reflect.Proxy类动态的根据您指定的所有接口生成一个class byte,该class会继承Proxy类,并实现所有你指定的接口(您在参数中传入的接口数组 ...
- 轻松理解 Java 静态代理/动态代理
目录 什么是代理模式 定义 代理模式的主要角色 优点 缺点 静态代理 动态代理 JDK原生动态代理 例子 分析 小结 CGLIB动态代理 例子 分析 final类型 其他方案 尾声 理解Java动态代 ...
- JAVA动态代理基础
Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM) 彻底理解JAVA动态代理 class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中. ...
- 详解java动态代理机制以及使用场景
详解java动态代理机制以及使用场景 https://blog.csdn.net/u011784767/article/details/78281384 深入理解java动态代理的实现机制 https ...
- JAVA动态代理的全面深层理解
Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过 ...
- JAVA动态代理模式(从现实生活角度理解代码原理)
所谓动态代理,即通过代理类:Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联. java动态代理主要是使用java.lang.reflect包中的两个 ...
随机推荐
- 后台登陆功能的实现 SESSION
控制器 <?php // 本类由系统自动生成,仅供测试用途 class IndexAction extends Action { public function index(){ $this-& ...
- (转)FFMPEG-数据结构解释(AVCodecContext,AVStream,AVFormatContext)
AVCodecContext 这是一个描述编解码器上下文的数据结构,包含了众多编解码器需要的参数信息 如果是单纯使用libavcodec,这部分信息需要调用者进行初始化:如果是使用整个FFMPEG库 ...
- bootstrap基础学习三篇
bootstrap的排版 1.标题 Bootstrap 中定义了所有的 HTML 标题(h1 到 h6)的样式 2.代码如下: <div class="container"& ...
- 【转】Win32 创建控件风格不是Win XP解决方案
有时候我有在用Win32 API来向窗体上添加控件时,通过CreateWindow或CreateWindowEx创建出来的控件的风格不像XP风格,而是像Windows 2000的风格,界面很难看.注意 ...
- shell命令技巧——文本去重并保持原有顺序
简单来说,这个技巧相应的是例如以下一种场景 假设有文本例如以下 cccc aaaa bbbb dddd bbbb cccc aaaa 如今须要对它进行去重处理.这个非常easy,sort -u就能够搞 ...
- PowerShell如何使用自定义公共函数
http://blog.csdn.net/flyliuweisky547/article/details/18565705
- iOS 关于 UIKit 专栏应该写在最前面的话
iOS 关于 UIKit 应该写在最前面的话 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协 ...
- Java Web项目BlogAutoGenerator编写日志1
使用的数据库是MySQL,所以首先要在MySQL中创建database和表.建立数据库article_db,建立表blog,如下: create database article_db DEFAULT ...
- Linux Kernel 4.7版本发布
导读 在经历了长达一周的惬意假日时光,大神Linus Torvalds宣布面向所有GNU/Linux操作系统发布Linux Kernel 4.7.Linux 4.7内核的研发历经2个多月,自今年5月2 ...
- Java使用BigDecimal解决浮点型运算丢失精度的问题
@Test public void test1(){ System.out.print(0.05+0.01); } @Test public void test2(){ BigDecimal b1 = ...