java动态代理是java语言的一项高级特性。在平时的项目开发中,可能很难遇到动态代理的案例。可是动态代理在不少框架中起着不可替代的做用,例如Spring的AOP。今天咱们就聊一聊java动态代理的实现原理。java
jdk对于动态代理的支持主要依赖于两个类:Proxy和InvocationHandler。咱们先看一下类图。设计模式
Subject类是主题类,定义了我要作什么。咱们须要代理的类即实现Subject接口的RealSubject。数组
1.InvocationHandler框架
InvocationHandler接口是jdk提供的接口,这个接口只有一个方法jvm
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
咱们先了解下InvocationHandler这个类是作什么。如下是java docide
* <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引用,即咱们想要真正执行的目标对象。post
2. Method method。Method是java reflection API的一部分。这里传入的method对象,是实际被调用的method方法。this
3. Object[] args。这是方法调用时传入的参数数组。spa
了解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方法是生成代理类的关键方法,代理类在程序运行的过程当中生成,于是叫作动态代理。
了解了这两个最重要的类以后,咱们须要经过一个实例来帮助咱们更好的理解动态代理的运行机制。
首先咱们建立一个Subject接口以及其实现类。
步骤1. 定义Subject
1 public interface Subject { 2
3 public void say(String str); 4 } 5
6 public class SubjectBean implements Subject { 7
8 @Override 9 public void say(String str) { 10 System.out.println(str); 11 } 12 }
Subject的say方法是咱们须要代理的方法。在该方法的先后咱们不妨作一些额外的操做。接下来咱们定义咱们的InvocationHandler。
步骤2. 定义InvocationHandler
1 public class MyInvocationHandle implements InvocationHandler { 2
3 Subject subject; 4
5 public MyInvocationHandle(Subject subject) { 6 this.subject = subject; 7 } 8
9 @Override 10 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 11 System.out.println("pre"); 12 method.invoke(subject, args); 13 System.out.println("post"); 14 return null; 15 } 16
17 }
经过构造器,把被代理的对象传入。
步骤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设计模式》