Java 动态代理机制
本篇文章引用源码默认为Java 8
Java动态代理把代理操作抽象成InvocationHandler
接口,实际上的代理类DynamicProxy
,实现了抽象主题Subject
,通过继承Proxy类获得组件InvocationHandler
,从而使用InvocationHandler
的方法代理RealSubject
的方法,下面是个例子。
例子
- 首先我们定义了一个Subject类型的接口,为其声明了3个方法:
1 | public interface Subject { |
- 接着,定义了一个类来实现这个接口,这个类就是我们的真实对象,RealSubject类:
1 | public class RealSubject implements Subject{ |
- 下一步,我们就要定义一个动态代理类了,实现 InvocationHandler 这个接口:
1 | public class MyInvocationHandler implements InvocationHandler { |
- 最后是Client类:
1 | public class Client { |
- 输出
1 | com.sun.proxy.$Proxy0 |
机制详解
在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。
InvocationHandler
每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一方法 invoke 方法。
1 | /* |
Proxy
Proxy类提供了静态方法用于创建动态代理类和实例,也是所有动态代理类的父类。
1 | // 静态方法创建动态代理类 |
动态代理类在运行期被创建时实现了被代理类所实现的一组接口,代理类中的组件中包含了实现InvocationHandler
接口的代理方法实例。对于被代理类方法的调用,都会被实现同样接口的动态代理类分发给内部的InvocationHandler
实例,被分发的参数包括:被代理类实例,反射的方法实例,以及方法的入参数组。
动态生成的代理类有以下特性:
- 如果所有的代理接口是public的,那么动态代理类是public,final的且不能是抽象类。
- 如果有一个代理接口是non-public的,那么动态代理类也是non-public的,final,且不为抽象类。
- 动态代理类的类名以”$Proxy”开头,具体类名未知。
- 动态代理类继承类
java.lang.reflect.Proxy
。 - 动态代理类在创建时,以相同的顺序实现被代理类实现的接口。
- 如果动态代理类实现了一个non-public接口,那么它会和该接口定义在同一个package下。否则,动态代理类的包名也是未确定的。
Proxy.isProxyClass
方法可以判断一个类是不是代理类,是的话返回true。
源码解析
Proxy类源码
Proxy 类的private内部类 ProxyClassFactory 实际生成动态代理类。
1 | // 摘自 openJDk |
1 | public static Object newProxyInstance(ClassLoader loader, |
生成的动态代理类源码
动态代理类源代码生成工具类:
1 | import java.io.FileOutputStream; |
动态代理类源代码:
1 |
|