Cglib 与 JDK动态代理的运行性能比较
- 格式:docx
- 大小:34.58 KB
- 文档页数:8
Cglib和jdk动态代理的区别及运⾏性能⽐较动态代理解决了⽅法之间的紧耦合,IOC解决了类与类之间的紧耦合!Cglib和jdk动态代理的区别?1、Jdk动态代理:利⽤拦截器(必须实现InvocationHandler)加上反射机制⽣成⼀个代理接⼝的匿名类,在调⽤具体⽅法前调⽤InvokeHandler来处理2、 Cglib动态代理:利⽤ASM框架,对代理对象类⽣成的class⽂件加载进来,通过修改其字节码⽣成⼦类来处理什么时候⽤cglib什么时候⽤jdk动态代理?1、⽬标对象⽣成了接⼝默认⽤JDK动态代理2、如果⽬标对象使⽤了接⼝,可以强制使⽤cglib3、如果⽬标对象没有实现接⼝,必须采⽤cglib库,Spring会⾃动在JDK动态代理和cglib之间转换JDK动态代理和cglib字节码⽣成的区别?1、JDK动态代理只能对实现了接⼝的类⽣成代理,⽽不能针对类2、Cglib是针对类实现代理,主要是对指定的类⽣成⼀个⼦类,覆盖其中的⽅法,并覆盖其中⽅法的增强,但是因为采⽤的是继承,所以该类或⽅法最好不要⽣成final,对于final类或⽅法,是⽆法继承的Cglib⽐JDK快?1、cglib底层是ASM字节码⽣成框架,但是字节码技术⽣成代理类,在JDL1.6之前⽐使⽤java反射的效率要⾼2、在jdk6之后逐步对JDK动态代理进⾏了优化,在调⽤次数⽐较少时效率⾼于cglib代理效率3、只有在⼤量调⽤的时候cglib的效率⾼,但是在1.8的时候JDK的效率已⾼于cglib4、Cglib不能对声明final的⽅法进⾏代理,因为cglib是动态⽣成代理对象,final关键字修饰的类不可变只能被引⽤不能被修改Spring如何选择是⽤JDK还是cglib?1、当bean实现接⼝时,会⽤JDK代理模式2、当bean没有实现接⼝,⽤cglib实现3、可以强制使⽤cglib(在spring配置中加⼊<aop:aspectj-autoproxy proxyt-target-class=”true”/>)⼀. Cglib原理动态⽣成⼀个要代理的⼦类,⼦类重写要代理的类的所有不是final的⽅法。
feign 底层原理Feign 底层原理Feign 是一个声明式的Web服务客户端,它使得编写Web服务客户端变得更加简单。
Feign 的底层原理主要涉及到动态代理、注解和编译时代码生成等技术。
本文将深入探讨Feign 的底层原理,以帮助读者更好地理解和使用 Feign。
一、动态代理动态代理是 Feign 实现的核心机制之一。
在使用 Feign 时,我们只需要定义一个接口,并使用注解来配置接口的调用方式和参数,然后Feign 就会根据接口定义生成一个实现类的代理对象。
当我们调用代理对象的方法时,实际上是通过代理对象将请求转发给远程的Web服务。
Feign 提供了多种代理实现方式,其中最常用的是基于 JDK 动态代理和基于 CGLIB 的动态代理。
JDK 动态代理需要目标类实现接口,而CGLIB 动态代理则不需要。
在Feign 中,默认使用的是基于JDK 动态代理。
二、注解注解是Feign 中另一个重要的概念。
通过使用注解,我们可以在接口上定义请求的URL、请求方法、请求参数等信息。
Feign 提供了多种用于请求配置的注解,包括@RequestMapping、@GetMapping、@PostMapping 等。
使用注解可以使得我们在接口中定义请求的方式更加简洁明了。
同时,注解也提供了丰富的配置选项,可以满足不同场景下的需求。
例如,我们可以通过@PathVariable 注解来绑定URL 中的参数,通过 @RequestParam 注解来绑定请求参数。
三、编译时代码生成编译时代码生成是 Feign 的另一个重要特性。
在使用 Feign 时,我们只需要定义一个接口,并使用注解来配置接口的调用方式和参数。
然后,Feign 会在编译时根据接口定义生成一个实现类的代理对象。
编译时代码生成的好处是,它可以在编译时进行类型检查和错误检查,避免在运行时出现错误。
同时,代码生成还可以优化请求的性能,减少不必要的网络开销。
基于SpringAOPproxyTargetClass的⾏为表现总结Spring AOP proxyTargetClass的⾏为要点列表形式proxyTargetClasstrue⽬标对象实现了接⼝ – 使⽤CGLIB代理机制⽬标对象没有接⼝(只有实现类) – 使⽤CGLIB代理机制false⽬标对象实现了接⼝ – 使⽤JDK动态代理机制(代理所有实现了的接⼝)⽬标对象没有接⼝(只有实现类) – 使⽤CGLIB代理机制表格形式proxyTargetClass⽬标对象特征代理效果true⽬标对象实现了接⼝使⽤CGLIB代理机制true⽬标对象没有接⼝(只有实现类)使⽤CGLIB代理机制false⽬标对象实现了接⼝使⽤JDK动态代理机制(代理所有实现了的接⼝)false⽬标对象没有接⼝(只有实现类)使⽤CGLIB代理机制proxy-target-class="true" 与proxy-target-class="false"的区别<tx:annotation-driven transaction-manager="transactionManager"proxy-target-class="true"/>注意:proxy-target-class属性值决定是基于接⼝的还是基于类的代理被创建。
如果proxy-target-class 属性值被设置为true,那么基于类的代理将起作⽤(这时需要cglib库)。
如果proxy-target-class 属值被设置为false或者这个属性被省略,那么标准的JDK 基于接⼝的代理将起作⽤。
即使你未声明 proxy-target-class="true" ,但运⾏类没有继承接⼝,spring也会⾃动使⽤CGLIB代理。
⾼版本spring⾃动根据运⾏类选择 JDK 或 CGLIB 代理以上为个⼈经验,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。
Cglib (code generate library)概述JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理。
JDK的动态代理用起来非常简单,但它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。
如果想代理没有实现接口的继承的类,该怎么办?CGLIB就是最好的选择。
CGlib是一个强大的,高性能,高质量的Code生成类库。
它可以在运行期扩展Java类与实现Java接口。
其底层是通过小而快的字节码处理框架ASM来转换字节码并生成新的类。
大部分功能实际上是asm所提供的,CGlib只是封装了asm,简化了asm的操作,实现了在运行期动态生成新的class。
CGlib被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截);最流行的OR Mapping工具hibernate也使用CGLIB来代理单端single-ended(多对一和一对一)关联(对集合的延迟抓取,是采用其他机制实现的);EasyMock和jMock是通过使用模仿(moke)对象来测试java代码的包,它们都通过使用CGLIB来为那些没有接口的类创建模仿(moke)对象。
CGLIB的APIsCGLIB包的基本代码很少,但学起来有一定的困难,主要是缺少文档,API描述过于简单,这也是开源软件的一个不足之处。
目前CGLIB的版本是cglib-2.2.jar,主要由一下部分组成:∙net.sf.cglib.core底层字节码处理类,他们大部分与ASM有关系。
∙net.sf.cglib.transform编译期或运行期类和类文件的转换∙net.sf.cglib.proxy实现创建代理和方法拦截器的类∙net.sf.cglib.reflect实现快速反射和C#风格代理的类∙net.sf.cglib.util集合排序工具类∙net.sf.cglib.beansJavaBean相关的工具类用CGLIB创建动态代理CGLIB包是在ASM之上的一个高级别的层。
简述Mybatis的插件运行原理,以及如何编写一个插件。
MyBatis 的插件是一种通过动态代理机制拦截方法调用的方式,对SQL 执行过程进行干预和增强。
插件可以在SQL 执行前后进行一些处理,例如打印 SQL 语句、统计执行时间、实现自定义的缓存逻辑等。
插件运行原理主要涉及动态代理和责任链模式。
插件运行原理:动态代理:MyBatis 使用JDK 动态代理或者CGLIB 动态代理来生成Mapper 接口的代理对象。
代理对象会拦截接口方法的调用,包括查询、更新等操作。
责任链模式:MyBatis 将所有的插件组成一个责任链,每个插件可以在SQL 执行前后进行干预。
当执行一个 SQL 语句时,责任链上的插件按照顺序执行。
Interceptor 接口:插件需要实现 MyBatis 的 Interceptor 接口。
Interceptor 接口定义了三个方法:intercept、plugin、setProperties。
intercept 方法用于实际的拦截逻辑,plugin 方法用于创建代理对象,setProperties 方法用于设置插件属性。
XML 配置文件中配置插件:在 MyBatis 的 XML 配置文件中,可以通过 <plugins> 元素配置插件。
指定插件的 Java 类和相关属性。
编写一个插件:编写一个插件通常包括以下步骤:实现 Interceptor 接口:javaCopy codepublic class MyPlugin implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 在这里实现拦截逻辑return invocation.proceed();}@Overridepublic Object plugin(Object target) {// 创建代理对象return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) { // 设置插件属性}}在 XML 配置文件中配置插件:xmlCopy code<plugins><plugin interceptor="com.example.MyPlugin"><!-- 配置插件的属性 --></plugin></plugins>Java 代码中使用插件:javaCopy code// 获取 SqlSessionFactorySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStr eam("mybatis-config.xml"));// 获取 SqlSessiontry (SqlSession sqlSession = sqlSessionFactory.openSession()) {// 获取 Mapper 接口的代理对象MyMapper myMapper = sqlSession.getMapper(MyMapper.class);// 在执行 SQL 语句时,插件的拦截逻辑会生效myMapper.someMethod();}通过插件,可以在 SQL 执行的不同阶段进行自定义的处理,以实现一些定制化的功能。
Spring⽇常笔记记录10--动态代理实现InvocationHandler动态代理动态代理是指,程序在整个运⾏构成中根本就不存在⽬标类的代理类,⽬标对象的代理对象只是由代理⽣成⼯具(不是真实定义的类)在程序运⾏时由JVM根据反射等机制动态⽣成的。
代理对象与⽬标对象的代理关系在程序运⾏时才确⽴。
⼀、JDK动态代理动态代理的实现⽅式常⽤的有两种:使⽤JDK的Proxy,与通过CGLIB⽣成代理。
jdk的动态要求⽬标对象必须实现接⼝,这是Java设计上的要求。
从jdk1.3以来,Java语⾔通过ng.reflect包提供三个⽀持代理模式Proxy,Method和InvocationHandler。
⼆、CGLIB动态代理第三⽅的⼯具库,创建代理对象,原理是继承。
通过继承⽬标类,创建⼦类。
⼦类就是代理对象,要求⽬标类不能是final的,⽅法也不能是final的三、JDK动态代理底层实现反射包 ng.reflect , ⾥⾯有三个类: InvocationHandler , Method, Proxy.1)InvocationHandler 接⼝(调⽤处理器):就⼀个⽅法invoke()invoke():表⽰代理对象要执⾏的功能代码。
你的代理类要完成的功能就写在invoke()⽅法中。
代理类完成的功能:1. 调⽤⽬标⽅法,执⾏⽬标⽅法的功能2. 功能增强,在⽬标⽅法调⽤时,增加功能。
2)⽅法原型:参数: Object proxy:jdk创建的代理对象,⽆需赋值。
Method method:⽬标类中的⽅法,jdk提供method对象的Object[] args:⽬标类中⽅法的参数, jdk提供的。
public Object invoke(Object proxy, Method method, Object[] args)1) InvocationHandler 接⼝:表⽰你的代理要⼲什么怎么⽤: 1.创建类实现接⼝InvocationHandler2.重写invoke()⽅法,把原来静态代理中代理类要完成的功能,写在这。
一、选择题:下面关于AOP 的说法错误的是(C )。
A.AOP 将散落在系统中的“方面”代码集中实现B.AOP 有助于提高系统的可维护性C.AOP 已经表现出了将要替代面向对象的趋势D.AOP 是一种设计模式,Spring 提供了一种实现1.在Spring 框架中,面向方面编程(AOP)的目标在于(C )。
A.编写程序时不用关心其依赖超件的实现B.将程序中涉及的公用问题集中解决C.封装JDBC 访训数据库的代码,简化数据访问层的得复性代码D.实现面面的“无刷新”2.依赖注入说法正确的是(A )。
A.依赖注入的目标是在代码之外管理程序组建间的依赖关系B.依赖注入即是“面向接口”的编程C.依赖注入是面向对象技术的替代品D.依赖注入的使用会增大程序的规模3.关于Spring 说法错误的是(D )。
A.Spring 是一个轻量级JAVA EE 的框架集合 B.Spring 是“依赖注入”模式的实现C.使用Spring 可以实现声明事务 D.Spring 提供了AOP 方式的日志4.下面(C )不是Spring AOP 中的通知类型。
A.前置通知B.后置通知C.代理通知D.异常通知5.Spring 提倡通过(C )实现松耦合。
A.容器 B.IOCC.AOPD.Spring 框架6.Spring 负责创建Bean 的实例并管理其生命周期,Bean 运行于Spring的(D ),无须知晓它的存在即可使用Spring 的部分特性。
A.框架B.服务器C.客户端D.容器7.有关Spring 中配置数据源,下列说法正确的是(C )。
A.配置数据源的bean 名字只能是dataSourceB.DataSource 接口位于java.sql 包中C.在一个spring 配置文件中可以配置多个数据源 D.DataSource 就是一个数据库连接8.下面关于切入点的说法不正确的是(B )。
A.是AOP 中一系列连接点的集合 B.在做AOP 时定义切入点是必须的C.在做AOP 时定义切入点不是必须的 D.可以用正则表达式来宣州切入点9.下面关于Spring 中的bean 的作用域,描述错误的是(B )。
完整的后端开发流程-深⼊浅出Java线程池:使⽤篇⼿动步骤⾛⼀种完整的后端开发流程服务端1、将远程仓库的jar包拷贝到本地仓库2、将项⽬代码拷贝到本地并建⽴路径能够执⾏编译3、编译打包项⽬(package)⾄项⽬下,项⽬跑起来后进⾏本地测试4、版本稳定后,上测试环境上测试环境1、将远程仓库的jar包拷贝到测试环境2、将本地的项⽬代码上传到测试环境 pom能建⽴路径执⾏mvn脚本进⾏编译打包3、编译打包项⽬(package)⾄项⽬下,项⽬跑起来后进⾏测试4、版本在测试环境稳定后,install⾄本地仓库,在上传⾄远程仓库5、不推荐嫌⿇烦直接上传本地jar包的⽅式,因为这样⽆法发现由于环境造成的错误⽽且传输速度没有直接编译的快客户端联调1、将远程仓库的jar包(包括刚刚上传的服务端jar) 拷贝到本地仓库2、将项⽬代码拷贝到本地并建⽴路径能够执⾏编译3、编译打包项⽬(package)⾄项⽬下,项⽬跑起来后进⾏本地测试4、项⽬注册⾄RPC服务中来访问跑在测试环境的服务端项⽬5、版本稳定后,上测试环境联调。
团队的技术栈,基于这个背景再展开后⾯将提到的⼏个问题,将会有更深刻的体会。
控制层基于SpringMvc,数据持久层基于JdbcTemplate⾃⼰封装了⼀套类MyBatis的Dao框架,视图层基于Velocity模板技术,其余组件基于SpringCloud全家桶。
问题1某应⽤发布以后开始报数据库连接池不够⽤异常,⽇志如下:1com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 60000, active 500, maxActive 500, creating 0 很明显这是数据库连接池满了,当时处于业务低峰期,所以很显然并不是由于流量突发造成的,另⼀种可能性是长事务导致,⼀般是事务中掺杂了外部⽹络调⽤,最终跟业务负责⼈⼀起排除了长事务的可能性。
代理模式的种类、原理及各种实例详解代理模式是开发中常⽤的⼀种设计模式,每⼀种设计模式的出现都会极⼤的解决某⽅⾯的问题,代理模式也是⼀样,本⽂将会⽤通俗的语⾔来解释什么是代理模式?代理模式的种类、代码⽰例、每种代理模式的优缺点和代理模式适⽤的场景。
代理模式是什么?⾸先我们⽤⼀个⼩故事来描述下什么是代理模式,这会让你更快的理解代理模式的相关⾓⾊,为后⾯的各种代理打下基础。
假如,你是⼀个⼤明星,⼈⽓很旺,粉丝也特别多。
因为⼈⽓⾼,所以很多商家想找你代⾔⼴告,但是想要找你代⾔的⼈特别多,每个商家你都需要进⾏商务洽谈,如果聊得不错决定合作,后续还需要签署很多合同⽂件、记录、备案等。
这么多商家找你代⾔,其中你只能选择其中⼏个代⾔,即便只选择⼏个,你也忙不过来。
于是你就想了⼀个办法,给⾃⼰找了⼀个经纪⼈,给经纪⼈制定标准让他去对接各商家,经纪⼈做事很认真负责,不仅剔除了很多不良的商家还对有资格的商家做了详细的记录,记录商家的代⾔费、商家详细信息、商家合同等信息。
于是在商务代⾔这件事情上你只需要专⼼代⾔拍⼴告,其他的事情交由经纪⼈⼀并处理。
分析下整个事件,可以知道,经纪⼈就是代理⼈,明星就是被代理⼈。
在明星的⼴告代⾔中,经纪⼈处理的商务洽谈和签约环节相当于代理,这就是代理模式在实际⽣活中的简单案例。
其实不⽌经纪⼈和明星,⽣活中还有很多⾏为本质就是代理模式,⽐如:某些⼤牌的饮料三级代理销售、酒⽔的省市县的代理⼈、三国时曹操挟天⼦以令诸侯等等。
说了这么多案例,都是关于代理模式的,那既然这么多⼈都在⽤代理模式,那代理模式⼀定解决了⽣活中的某些棘⼿的问题,那究竟是什么问题呢?在明星和经纪⼈这个案例中,因为把代⾔这个商业⾏为做了细分,让明星团队中每个⼈负责代⾔的⼀部分,使每⼈只需要专注于⾃⼰的事,提⾼每个⼈的专业度的同时,也提⾼了效率,这就叫专业,专⼈专事。
因为经纪⼈专注⼴告代⾔的代理⾏为,商业经验丰富,所以经纪⼈也可以⽤他的专业知识为其他明星做⼴告代⾔的代理,这就叫能⼒复⽤。
代理模式实现⽅式及优缺点对⽐代理模式最典型的应⽤就是AOP,本⽂结合主要讲解了代理模式的⼏种实现⽅式:静态代理和动态代理,这⾥动态代理⼜可以分为jdk代理和Cglib代理,另外,本⽂也对这⼏种代理模式的优缺点进⾏了对⽐。
代理,顾名思义,即代替被请求者来处理相关事务。
代理对象⼀般会全权代理被请求者的全部只能,客户访问代理对象就像在访问被请求者⼀样,虽然代理对象最终还是可能会访问被请求者,但是其可以在请求之前或者请求之后进⾏⼀些额外的⼯作,或者说客户的请求不合法,直接拒绝客户的请求。
如下图所⽰为代理模式的⼀份简图:代理模式的⾓⾊:ISubject:代理者与被代理者共同实现的接⼝,可以理解为需要代理的⾏为;SubjectImpl:被代理者,其为具有某种特定⾏为的实现者;SubjectProxy:代理者,其会全权代理SubjectImpl所具有的功能,在实现其功能的基础上做⼀些额外的⼯作;Client:客户端,客户端访问代理者与访问被代理者具有类似的效果,其⽆法区分访问的是代理者还是被代理者。
1. 静态代理静态代理模式也即上图中描述的这种模式,从图中可以看出,SubjectProxy保存⼀个ISubject实例,当客户端调⽤SubjectProxy的request()⽅法时,其除了做额外的⼯作之外,还会调⽤ISubject实例的request()⽅法。
如下是这三个类的⼀个简单实现:public interface ISubject {void request();}public class SubjectImpl implements ISubject {@Overridepublic void request() {System.out.println("request SubjectImpl.");}}public class SubjectProxy implements ISubject {private ISubject target;public SubjectProxy(ISubject target) {this.target = target;}@Overridepublic void request() {System.out.println("before safety check.");target.request();System.out.println("after safety check.");}}可以看到,代理对象在调⽤被代理对象的⽅法之前和之后都打印了相关的语句。
都说Cglib 创建的动态代理的运行性能比JDK 动态代理能高出大概10 倍,今日抱着怀疑精神验证了一下,发现情况有所不同,遂贴出实验结果,以供参考和讨论。
代码很简单,首先,定义一个Test 接口,和一个实现TestImpl 。
Test 接口仅定义一个方法test,对传入的int 参数加1 后返回。
代码如下:package my.test;publicinterface Test {publicint test(int i);}package my.test;publicclass TestImpl implements Test{publicint test(int i) {return i+1;}}然后,定义了三种代理的实现:装饰者模式实现的代理(decorator),JDK 动态代理(dynamic proxy) 和Cglib 动态代理(cglib proxy)。
代码如下:package my.test;publicclass DecoratorTest implements Test{private Test target;public DecoratorTest(Test target) {this.target = target;}publicint test(int i) {return target.test(i);}}package my.test;import ng.reflect.InvocationHandler;import ng.reflect.Method;import ng.reflect.Proxy;publicclass DynamicProxyTest implements InvocationHandler {private Test target;private DynamicProxyTest(Test target) {this.target = target;}publicstatic Test newProxyInstance(Test target) {return (Test) Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoad er(),new Class<?>[] { Test.class },new DynamicProxyTest(target));}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {return method.invoke(target, args);}}package my.test;import ng.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;publicclass CglibProxyTest implements MethodInterceptor {private CglibProxyTest() {}publicstatic<T extends Test> Test newProxyInstance(Class<T> targetInstanceClazz){Enhancer enhancer = new Enhancer();enhancer.setSuperclass(targetInstanceClazz);enhancer.setCallback(new CglibProxyTest());return (Test) enhancer.create();}public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {return proxy.invokeSuper(obj, args);}}以TestImpl 的调用耗时作为基准,对比通过其它三种代理进行调用的耗时。
测试代码如下:package my.test;import java.util.LinkedHashMap;import java.util.Map;publicclass ProxyPerfTester {publicstaticvoid main(String[] args) {//创建测试对象;Test nativeTest = new TestImpl();Test decorator = new DecoratorTest(nativeTest);Test dynamicProxy =DynamicProxyTest.newProxyInstance(nativeTest);Test cglibProxy =CglibProxyTest.newProxyInstance(TestImpl.class);//预热一下;int preRunCount = 10000;runWithoutMonitor(nativeTest, preRunCount);runWithoutMonitor(decorator, preRunCount);runWithoutMonitor(cglibProxy, preRunCount);runWithoutMonitor(dynamicProxy, preRunCount);//执行测试;Map<String, Test> tests = new LinkedHashMap<String, Test>(); tests.put("Native ", nativeTest);tests.put("Decorator", decorator);tests.put("Dynamic ", dynamicProxy);tests.put("Cglib ", cglibProxy);int repeatCount = 3;int runCount = 1000000;runTest(repeatCount, runCount, tests);runCount = 50000000;runTest(repeatCount, runCount, tests);}privatestaticvoid runTest(int repeatCount, int runCount, Map<String, Test> tests){System.out.println(String.format("\n==================== run test : [repeatCount=%s] [runCount=%s] [java.version=%s]====================", repeatCount, runCount,System.getProperty("java.version")));for (int i = 0; i < repeatCount; i++) {System.out.println(String.format("\n--------- test : [%s] ---------", (i+1)));for (String key : tests.keySet()) {runWithMonitor(tests.get(key), runCount, key);}}}privatestaticvoid runWithoutMonitor(Test test, int runCount) {for (int i = 0; i < runCount; i++) {test.test(i);}}privatestaticvoid runWithMonitor(Test test, int runCount, String tag) { long start = System.currentTimeMillis();for (int i = 0; i < runCount; i++) {test.test(i);}long end = System.currentTimeMillis();System.out.println("["+tag + "] Elapsed Time:" + (end-start) + "ms");}}测试用例分别在jdk6、jdk7、jdk8 下进行了测试,每次测试分别以1,000,000 和50,000,000 循环次数调用test 方法,并重复3次。
jdk6 下的测试结果如下:==================== run test : [repeatCount=3] [runCount=1000000] [java.version=1.6.0_45] ====================--------- test : [1] ---------[Native ] Elapsed Time:2ms[Decorator] Elapsed Time:12ms[Dynamic ] Elapsed Time:31ms[Cglib ] Elapsed Time:31ms--------- test : [2] ---------[Native ] Elapsed Time:7ms[Decorator] Elapsed Time:7ms[Dynamic ] Elapsed Time:31ms[Cglib ] Elapsed Time:27ms--------- test : [3] ---------[Native ] Elapsed Time:7ms[Decorator] Elapsed Time:6ms[Dynamic ] Elapsed Time:23ms[Cglib ] Elapsed Time:29ms==================== run test : [repeatCount=3] [runCount=50000000] [java.version=1.6.0_45] ====================--------- test : [1] ---------[Native ] Elapsed Time:212ms[Decorator] Elapsed Time:226ms[Dynamic ] Elapsed Time:1054ms[Cglib ] Elapsed Time:830ms[Native ] Elapsed Time:184ms[Decorator] Elapsed Time:222ms[Dynamic ] Elapsed Time:1020ms[Cglib ] Elapsed Time:826ms--------- test : [3] ---------[Native ] Elapsed Time:184ms[Decorator] Elapsed Time:208ms[Dynamic ] Elapsed Time:979ms[Cglib ] Elapsed Time:832ms测试结果表明:jdk6 下,在运行次数较少的情况下,jdk动态代理与cglib 差距不明显,甚至更快一些;而当调用次数增加之后,cglib 表现稍微更快一些,然而仅仅是“稍微”好一些,远没达到10 倍差距。