理解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包中的两个 ...
随机推荐
- OS X删除自带的safari和facetime等程序
打开终端 cd /Applications/ //在应用程序文件目录删除苹果自带的程序 sudo rm -rf Safari.app/ //删除safari浏览器 sudo rm -rf Mail.a ...
- 第二百五十五节,Bootstrap项目实战--关于
Bootstrap项目实战--关于 html <!DOCTYPE html> <html lang="zh-cn"> <head> <me ...
- linux的tcz文件怎么安装?
.tcz文件是Tiny core linux 应用安装包文件启动Tiny core linux后,可以使用tce-load命令安装软件如: tce-load -i /tmp/bftpd.tcz 转自: ...
- 《Java并发编程实战》第八章 线程池的使用 读书笔记
一.在任务与运行策略之间的隐性解耦 有些类型的任务须要明白地指定运行策略,包含: . 依赖性任务.依赖关系对运行策略造成约束.须要注意活跃性问题. 要求线程池足够大,确保任务都能放入. . 使用线程封 ...
- Nginx配置里的fastcgi_index和index
在配置nginx时有时会遇到, 所以记录一下 location ^~ /wechat/ { index index.php; fastcgi_pass 127.0.0.1:9000; fastcgi_ ...
- [转]C# 超高速高性能写日志 代码开源
1.需求 需求很简单,就是在C#开发中高速写日志.比如在高并发,高流量的地方需要写日志.我们知道程序在操作磁盘时是比较耗时的,所以我们把日志写到磁盘上会有一定的时间耗在上面,这些并不是我们想看到的 ...
- Oracle的归档日志
归档模式的特点和要求 在归档模式下,当LGWR后台进程的写操作从一个重做日志组切换到另一个重做日志组后,归档写后台进程(ARCH/ARCRn)就会将原来的重做日志的信息复制到归档日志文件中. 可以把归 ...
- Docker(1)在CentOS上的安装与卸载
一. Docker的安装 CentOS7 上安装: 1. 卸载旧版本 $ sudo yum remove docker \ docker-client \ docker-client-latest ...
- IOS7开发~新UI学起(二)
本文转载至 http://blog.csdn.net/lizhongfu2013/article/details/9133281 1.UINavigationBar: NSDictionary* at ...
- IOS 设置ios中DatePicker的日期为中文格式
设置ios中DatePicker的日期为中文格式 1.在模拟器中的“设置”-“通用”-“多语言环境”-“语言”设置为“简体中文”, 2.“区域格式”设置为“中国”.