理解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包中的两个 ...
随机推荐
- 三种CSS方法实现loadingh点点点的效果
我们在提交数据的时候,在开始提交数据与数据提交成功之间会有一段时间间隔,为了有更好的用户体验,我们可以在这个时间段添加一个那处点点点的动画,如下图所示: 汇总了一下实现这种效果主要有三种方法: 第一种 ...
- Java的图形界面依然是跨平台的
Awt:抽象窗口工具箱,它由三部分组成: ①组件:界面元素: ②容器:装载组件的容器(例如窗体): ③布局管理器:负责决定容器中组件的摆放位置. 图形界面的应用分四步: ① 选择一个容器: ⑴wind ...
- vs2010更新EF模型时报错
尝试从数据库进行更新时,遇到类型为“Microsoft.VSDesigner.Data.Local.ConnectionStringConverterServiceException”的异常.异常消息 ...
- sdut 2154:Shopping(第一届山东省省赛原题,水题)
Shopping Time Limit: 1000MS Memory limit: 65536K 题目描述 Saya and Kudo go shopping together.You can ass ...
- 判断uiscrollView滑到底部
本文转载至 http://blog.csdn.net/cerastes/article/details/39612177 -(void)scrollViewDidScroll:(UIScrollVi ...
- json的循环
通过for in: var json = {width: '200px', height: '200px', background: 'green'}; var i = ''; for(i in js ...
- JZOJ.5307【NOIP2017模拟8.18】偷窃
Description
- 帧动画和骨骼json、极速、二进制对比
对比总结: 1. 帧动画的效率最高,但是图片超过一定帧数,资源图片非常大.比较适合帧数少,大量动画存在,要求效率高的场合. 骨骼json效率较低,已经不推荐使用. 骨骼极速,不支持网格等. 骨骼二进制 ...
- CH5105 Cookies【贪心】【线性dp】
5105 Cookies 0x50「动态规划」例题 描述 圣诞老人共有M个饼干,准备全部分给N个孩子.每个孩子有一个贪婪度,第 i 个孩子的贪婪度为 g[i].如果有 a[i] 个孩子拿到的饼干数比第 ...
- Codeforces Round #513-ABCD
ABC现场做出,涨了八十几分吧.D有点思路不知道怎么实现,赛后看题解发现巨简单,想得太复杂了.蓝瘦. A----http://codeforces.com/contest/1060/problem/A ...