JDK动态代理浅析

        上一篇用了JDK的动态代理,说JDK中的动态代理是通过反射类Proxy以及InvocationHandler回调接口实现的,却有些问题一直没有想明白。比如InvocationHandler的invoke方法是由谁来调用的,代理对象是怎么生成的,动态代理的实现步骤等等。

下面先来说说动态代理的实现步骤:

(1)   实现InvocationHandler接口创建自己的调用处理器;

(2)   给Proxy类提供ClassLoader和代理接口类型数组创建动态代理类;

(3)   以调用处理器类型为参数,利用反射机制得到动态代理类的构造函数;

(4)   以调用处理器对象为参数,利用动态代理类的构造函数创建动态代理类对象

Java代码:

<span style="font-family:Microsoft YaHei;">// InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
// 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用
InvocationHandler handler = new InvocationHandlerImpl(..); 

// 通过 Proxy 为包括 Interface 接口在内的一组接口动态创建代理类的类对象
Class clazz = Proxy.getProxyClass(classLoader, new Class[] { Interface.class, ... }); 

// 通过反射从生成的类对象获得构造函数对象
Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class }); 

// 通过构造函数对象创建动态代理类实例
Interface Proxy = (Interface)constructor.newInstance(new Object[] { handler }); </span>
Proxy类的静态方法newProxyInstance对后三步做了封装,简化了动态代理对象的获取过程。简化后的java代码如下:
<span style="font-family:Microsoft YaHei;">// InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
InvocationHandler handler = new InvocationHandlerImpl(..); 

// 通过 Proxy 直接创建动态代理类实例
Interface proxy = (Interface)Proxy.newProxyInstance( classLoader, 
new Class[] { Interface.class },  handler ); </span>
     下面我只简单介绍一下在代理对象调用方法并返回结果时用到的invoke ( Object proxy, Methodmethod, Object[] args) throws  Throwable方法的参数。

proxy

代理对象;

method

要调用的 Method实例。Method对象的声明是在该代理对象实现的接口中定义了的。

args

包含传入代理实例上方法调用的参数值数组,如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类(如java.lang.Integerjava.lang.Boolean)的实例中。

return

从代理实例的方法调用返回的值。如果接口方法的声明返回类型是基本类型,则此方法返回的值一定是相应基本包装对象类的实例;否则,它一定是可分配到声明返回类型的类型。如果此方法返回的值为null并且接口方法的返回类型是基本类型,则代理实例上的方法调用将抛出NullPointerException。否则,如果此方法返回的值与上述接口方法的声明返回类型不兼容,则代理实例上的方法调用将抛出ClassCastException

Throws

Throwable:从代理实例上的方法调用抛出的异常。该异常的类型必须可以分配到在接口方法的throws子句中声明的任一异常类型或未经检查的异常类型java.lang.RuntimeExceptionjava.lang.Error。如果此方法抛出经过检查的异常,该异常不可分配到在接口方法的throws子句中声明的任一异常类型,代理实例的方法调用将抛出包含此方法曾抛出的异常的UndeclaredThrowableException

        对于是由谁来调用InvocationHandler的invoke方法,可以参考一下这个博客链接:http://rejoy.iteye.com/blog/1627405,讲解的很详细。从讲解中可以看出,其实动态代理的核心其实就是代理对象的生成,即Proxy.newProxyInstance(classLoader, proxyInterface, handler)

       动态代理在运行期通过接口动态生成代理类,这为其带来了一定的灵活性,但这个灵活性却带来了两个问题。

       第一代理类必须实现一个接口,如果没实现接口会抛出一个异常。

       第二性能影响,因为动态代理使用反射的机制实现的,首先反射肯定比直接调用要慢,经过测试大概每个代理类比静态代理多出10几毫秒的消耗。其次使用反射大量生成类文件可能引起Full GC造成性能影响。因为字节码文件加载后会存放在JVM运行时区的方法区(或者叫持久代)中,当方法区满的时候,会引起Full GC。所以当你大量使用动态代理时,可以将持久化设置大一些,减少Full GC次数。

      而如果采用CgLib 实现动态代理,它一方面不必非要实现一个接口,另一方面性能也比JDK动态代理性能好。下篇博客我们就讲一下CgLib 实现动态代理,敬请期待吧!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值