Java程序性能优化-代理模式(6)

Java程序性能优化-代理模式(6),第1张

  代理模式( )

以上代码分别生成了 种代理 并对生成的代理类进行高频率的调用 最后输出各个代理类的创建耗时 动态类类名和方法调用耗时 结果如下

createJdkProxy:

JdkProxy class:$Proxy

callJdkProxy:

createCglibProxy:

CglibProxy class:$javatuning ch proxy IDBQuery$$EnhancerByCGLIB$$b a bbf

callCglibProxy:

createJavassistDynProxy:

JavassistDynProxy class:javatuning ch proxy IDBQuery_$$_javassist_

callJavassistDynProxy:

createJavassistBytecodeDynamicProxy:

JavassistBytecodeDynamicProxy class:javatuning ch proxy IDBQueryJavaassistBytecodeProxy

callJavassistBytecodeDynamicProxy:

可以看到 JDK的动态类创建过程最快 这是因为在这个内置实现中defineClass()方法被定义为native实现 故性能高于其他几种实现 但在代理类的函数调用性能上 JDK的动态代理就不如CGLIB和Javassist的基于动态代码的代理 而Javassist的基于代理工厂的代理实现 代理的性能质量最差 甚至不如JDK的实现 在实际开发应用中 代理类的方法调用频率通常要远远高于代理类的实际生成频率(相同类的重复生成会使用cache) 故动态代理对象的方法调用性能应该作为性能的主要关注点

注意 就动态代理的方法调用性能而言 CGLIB和Javassist的基于动态代码的代理都优于JDK自带的动态代理 此外 JDK的动态代理要求代理类和真实主题都实现同一个接口 而CGLIB和Javassist没有强制要求

Hibernate中代理模式的应用

用代理模式实现延迟加载的一个经典应用就在Hibernate框架中 当Hibernate加载实体bean时 并不会一次性将数据库所有的数据都装载 默认情况下 它会采取延迟加载的机制 以提高系统的性能 Hiberante中的延迟加载主要有两种 一是属性的延迟加载 二是关联表的延时加载 这里以属性的延迟加载为例 简单阐述Hibernate是如何使用动态代理的

假定有用户模型

public class User implements java io Serializable {

private Integer id

private String name

private int age

//省略getter和setter

使用以下代码 通过Hibernate加载一条User信息

public static void main(String[] args) throws SecurityException

NoSuchFieldException

IllegalArgumentException

IllegalAccessException {

//从数据库载入ID为 的用户

User u=(User)HibernateSessionFactory getSession() load(User class )

//打印类名称

System out println( Class Name: +u getClass() getName())

//打印父类名称

System out println( Super Class Name: +u getClass() getSuperclass()

getName())

//实现的所有接口

Class[] ins=u getClass() getInterfaces()

for(Class cls:ins){

System out println( interface: +cls getName())

}

System out println(u getName())

}

       返回目录 Java程序性能优化 让你的Java程序更快 更稳定

编辑推荐

       Java程序设计培训视频教程

       J EE高级框架实战培训视频教程

       J ME移动开发实战教学视频

Visual C++音频/视频技术开发与实战

Oracle索引技术

lishixinzhi/Article/program/Java/gj/201311/27829

  代理模式( )

在以上代码中 使用CtField make()方法和CtNewMehod make()方法在运行时生成了代理类的字段和方法 这些逻辑由Javassist的CtClass对象处理 将Java代码转换为对应的字节码 并生成动态代理类的实例

注意 与静态代理相比 动态代理可以很大幅度地减少代码行数 并提升系统的灵活性

在Java中 动态代理类的生成主要涉及对ClassLoader的使用 这里以CGLIB为例 简要阐述动态类的加载过程 使用CGLIB生成动态代理 首先需要生成Enhancer类实例 并指定用于处理代理业务的回调类 在Enhancer create()方法中 会使用DefaultGeneratorStrategy Generate()方法生成动态代理类的字节码 并保存在byte数组中 接着使用ReflectUtils defineClass()方法 通过反射 调用ClassLoader defineClass()方法 将字节码装载到ClassLoader中 完成类的加载 最后使用ReflectUtils newInstance()方法 通过反射 生成动态类的实例 并返回该实例 无论使用何种方法生成动态代理 虽然实现细节不同 但主要逻辑都如图 所示

图   实现动态代理的基本步骤

前文介绍的几种动态代理的生成方法 性能有一定差异 为了能更好地测试它们的性能 去掉DBQuery类中的sleep()代码 并使用以下方法测试

public static final int CIRCLE=

public static void main(String[] args) throws Exception {

IDBQuery d=null

long begin=System currentTimeMillis()

d=createJdkProxy()                      //测试JDK动态代理

System out println( createJdkProxy: +(System currentTimeMillis() beg    in))

System out println( JdkProxy class: +d getClass() getName())

begin=System currentTimeMillis()

for(int i= i<CIRCLEi++)

d request()

System out println( callJdkProxy: +(System currentTimeMillis() begin    ))

begin=System currentTimeMillis()

d=createCglibProxy()                    //测试CGLIB动态代理

System out println( createCglibProxy: +(System currentTimeMillis() b    egin))

System out println( CglibProxy class: +d getClass() getName())

begin=System currentTimeMillis()

for(int i= i<CIRCLEi++)

d request()

System out println( callCglibProxy: +(System currentTimeMillis() beg    in))

begin=System currentTimeMillis()

d=createJavassistDynProxy()             //测试Javaassist动态代理

System out println( createJavassistDynProxy: +(System currentTimeMil    lis() begin))

System out println( JavassistDynProxy class: +d getClass() getName())

begin=System currentTimeMillis()

for(int i= i<CIRCLEi++)

d request()

System out println( callJavassistDynProxy: +(System currentTimeMilli    s() begin))

begin=System currentTimeMillis()

d=createJavassistBytecodeDynamicProxy()     //测试Javassist动态代理

System out println( createJavassistBytecodeDynamicProxy: +(System cu    rrentTimeMillis() begin))

System out println( JavassistBytecodeDynamicProxy class: +d getClass()

getName())

begin=System currentTimeMillis()

for(int i= i<CIRCLEi++)

d request()

System out println( callJavassistBytecodeDynamicProxy: +(System curr    entTimeMillis() begin))

}

       返回目录 Java程序性能优化 让你的Java程序更快 更稳定

编辑推荐

       Java程序设计培训视频教程

       J EE高级框架实战培训视频教程

       J ME移动开发实战教学视频

Visual C++音频/视频技术开发与实战

Oracle索引技术

lishixinzhi/Article/program/Java/gj/201311/27830

文件名以.Java结尾,名称和文件名保持一致。

检查环境变量是否设置,在cmd控制台中输入java-version看是否有输出Java版本号。

先讲Java编译为class文件:javacTest.java。

运行class文件:javaTest。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/7784917.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-09
下一篇 2023-04-09

发表评论

登录后才能评论

评论列表(0条)

保存