a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 136|回复: 0

[专业语言] Java认证辅导之关于用动态代理进行修饰(3)

[复制链接]
发表于 2012-8-4 12:44:44 | 显示全部楼层 |阅读模式
Java认证辅导之关于用动态代理进行修饰(3)6 ~. {1 R  u: P; E1 Z* S" L4 h

  w6 |6 U( S+ U9 c# i7 o3 c8 b9 o% a
清单 7 显示的动态代理检查被调用方法的名称,并通过查询或修改属性图直接实现 getter 和 setter 方法。现在,这一个代理类就能实现多个 JavaBean 风格接口的对象。1 g: [; I% }5 c: V3 U7 I& c
清单 7. 用于把 getter 和 setter 分派给 Map 的动态代理类
. V! M; U8 q% J$ Q8 h; }" spublic class JavaBeanProxyFactory { private static class JavaBeanProxy implements InvocationHandler { Map《String, Object》 properties = new HashMap《String, Object》(); public JavaBeanProxy(Map《String, Object》 properties) { this.properties.putAll(properties); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String meth = method.getName(); if (meth.startsWith(“get”)) { String prop = meth.substring(3); Object o = properties.get(prop); if (o != null && !method.getReturnType().isInstance(o)) throw new ClassCastException(o.getClass().getName() + “ is not a ” + method.getReturnType().getName()); return o; } else if (meth.startsWith(“set”)) { // Dispatch setters similarly } else if (meth.startsWith(“is”)) { // Alternate version of get for boolean properties } else { // Can dispatch non get/set/is methods as desired } } } public static《T》 T getProxy(Class《T》 intf, Map《String, Object》 values) { return (T) Proxy.newProxyInstance (JavaBeanProxyFactory.class.getClassLoader(), new Class[] { intf }, new JavaBeanProxy(values)); } }* _0 P+ f; g: N
虽然因为反射在 Object 上工作会有潜在的类型安全性上的损失,但是,JavaBeanProxyFactory 中的 getter 处理会进行一些必要的额外的类型检测,就像我在这里用 isInstance() 对 getter 进行的检测一样。
5 j. n6 I5 ?0 {: w性能成本6 |- ~3 y: n1 U
正如已经看到的,动态代理拥有简化大量代码的潜力 —— 不仅能替代许多生成的代码,而且一个代理类还能代替多个手写的类或生成的代码。什么是成本呢?因为反射地分派方法而不是采用内置的虚方法分派,可能有一些性能上的成本。在早期的 JDK 中,反射的性能很差(就像早期 JDK 中几乎其他每件事的性能一样),但是在近 10 年,反射已经变得快多了。
2 a& j( a3 B6 I7 ]  M; M. F) }不必进入基准测试构造的主题,我编写了一个简单的、不太科学的测试程序,它循环地把数据填充到 Set,随机地对 Set进行插入、查询和删除元素。我用三个 Set 实现运行它:一个未经修饰的 HashSet,一个手写的、只是把所有方法转发到底层的 HashSet 的 Set 适配器,还有一个基于代理的、也只是把所有方法转发到底层 HashSet 的 Set 适配器。每次循环迭代都生成若干随机数,并执行一个或多个 Set 操作。手写的适配器比起原始的 HashSet 只产生很少百分比的性能负荷(大概是因为 JVM 级有效的内联缓冲和硬件级的分支预测);代理适配器则明显比原始 HashSet 慢,但是开销要少于两个量级。
9 @, H: ~1 `' K% S& q我从这个试验得出的结论是:对于大多数情况,代理方式即使对轻量级方法也执行得足够好,而随着被代理的操作变得越来越重量级(例如远程方法调用,或者使用序列化、执行 IO 或者从数据库检索数据的方法),代理开销就会有效地接近于 0。当然也存在一些代理方式的性能开销无法接受的情况,但是这些通常只是少数情况。
' d1 P2 P! ~" v2 m+ E2 T结束语$ S% O6 J! m& n
动态代理是强大而未充分利用的工具,可以用于实现许多设计模式,包括 Proxy、Decorator 和 Adapter。这些模式基于代理的实现容易编写,更难出错,并且具备更好的通用性;在许多情况下,一个动态代理类可以充当所有接口的 Decorator 或 Proxy,这样就不用每个接口都编写一个静态类。除了最关注性能的应用程序之外,动态代理方式可能比手写或机器生成 stub 的方式更可取。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Woexam.Com ( 湘ICP备18023104号 )

GMT+8, 2024-5-13 21:14 , Processed in 0.185895 second(s), 21 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表