原文:http://blog.csdn.net/liutengteng130/article/details/46565309
动态代理是指在运行时,动态生成代理类。代理类的字节码将在运行时生成并载入当前的ClassLoader.
生成动态代理类的方法很多,如JDK自带的动态代理、CGLIB、Javassist或者ASM库。
JDK动态代理使用简单,它内置在JDK中,因此不需要引入第三方Jar包,但相对功能比较弱。CGLIB和Javassist都是高级的字节码生成库,总体性能比JDK自带的动态代理好,而且功能十分强大。ASM是低级的字节码生成工具,使用ASM已经近乎在于使用Javabytecode编程,对开发人员要求较高,也是性能最好的一种动态代理生辰工具。但ASM的使用是在过于繁琐,而且性能也没有数量级的提升,与CGLIB等高级字节码生成工具相比,ASM程序的可维护性也较差。
JDK实现
1、步骤
1)通过实现InvocationHandler接口创建自己的调用处理器
2)通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理类
3)通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型
4)通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入
2、创建代理
-
-
-
InvocationHandlerhandler=newInvocaitonHandlerImpl(..);
-
-
-
Classclazz=Proxy.getProxyClass(classLoader,newClass[]{Interface.class,...});
-
-
-
Constructorconstructor=clazz.getConstructor(newClass[]{InvocationHandler.class});
-
-
-
InterfaceProxy=(Interface)constructor.newInstance(newObject[]{handler});
-
-
-
-
InvocaitonHandlerhandler=newInvocationHandlerImpl(..);
-
-
-
nterfaceproxy=(Interface)Proxy.newProxyInstance(classLoader,newClass[]{Interface.class},handler);
3、代码
-
-
-
-
-
-
publicinterfaceIDBQuery{
-
-
Stringrequest();
-
}
-
-
-
-
-
-
-
publicclassDBQueryimplementsIDBQuery{
-
-
-
publicDBQuery(){
-
try{
-
Thread.sleep(1000);
-
}catch(InterruptedExceptione){
-
e.printStackTrace();
-
}
-
}
-
-
@Override
-
publicStringrequest(){
-
-
return"requeststring";
-
}
-
-
}
-
-
-
-
-
-
-
publicclassJdkDbQueryHandlerimplementsInvocationHandler{
-
-
IDBQueryreal=null;
-
-
-
-
-
@Override
-
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)
-
throwsThrowable{
-
if(real==null)
-
real=newDBQuery();
-
returnreal.request();
-
}
-
-
-
-
-
-
publicstaticIDBQuerycreateJdkProxy(){
-
-
-
-
-
-
IDBQueryjdkProxy=(IDBQuery)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),newClass[]{IDBQuery.class},newJdkDbQueryHandler());
-
returnjdkProxy;
-
}
-
-
-
}
执行过程:
如图,目标对象的方法调用被Proxy拦截,在InvocationHandler中的回调方法中通过反射调用,这种动态代理的方法实现了对类的方法的运行时修改。
JDK动态代理有个缺点,那就是不能对类进行代理,只能对接口进行代理,如果我们的类没有实现任何接口,那么就不能使用这种方式进行动态代理(因为$Proxy()这个类集成了Proxy,Java的集成不允许出现多个父类)。准确的说这不应该是缺点,一个良好的系统,每个类都应该有一个接口与之对应。针对接口编程。
CGLIB实现
-
packagecom.ltt.dynamic;
-
-
importjava.lang.reflect.Method;
-
-
importnet.sf.cglib.proxy.Enhancer;
-
importnet.sf.cglib.proxy.MethodInterceptor;
-
importnet.sf.cglib.proxy.MethodProxy;
-
-
-
-
-
-
-
publicclassCglibDbQueryInterceptorimplementsMethodInterceptor{
-
IDBQueryreal=null;
-
-
-
-
-
@Override
-
publicObjectintercept(Objectarg0,Methodarg1,Object[]arg2,
-
MethodProxyarg3)throwsThrowable{
-
if(real==null){
-
real=newDBQuery();
-
returnreal.request();
-
}
-
returnnull;
-
}
-
-
-
-
-
-
publicstaticIDBQuerycreateCglibProxy(){
-
Enhancerenhancer=newEnhancer();
-
-
enhancer.setCallback(newCglibDbQueryInterceptor());
-
-
enhancer.setInterfaces(newClass[]{IDBQuery.class});
-
-
IDBQuerycglibProxy=(IDBQuery)enhancer.create();
-
returncglibProxy;
-
}
-
-
-
}
Javassist实现
一种是使用代理工厂创建,另一种通过使用动态代码创建。使用代理工厂创建时,方法与CGLIB类似,也需要实现一个用于代理逻辑处理的Handler:例如createJavassistDynProxy();使用动态代码创建,生成字节码,这种方式可以非常灵活,甚至可以在运行时生成业务逻辑,如createJavassistBytecodeDynamicProxy()方法。
-
-
-
-
-
-
publicclassJavassistDynDbQueryHandlerimplementsMethodHandler{
-
-
IDBQueryreal=null;
-
-
-
-
-
-
@Override
-
publicObjectinvoke(Objectarg0,Methodarg1,Methodarg2,Object[]arg3)
-
throwsThrowable{
-
if(real==null)
-
real=newDBQuery();
-
returnreal.request();
-
-
}
-
-
-
-
-
-
-
publicstaticIDBQuerycreateJavassistDynProxy()throwsException{
-
ProxyFactoryproxyFactory=newProxyFactory();
-
proxyFactory.setInterfaces(newClass[]{IDBQuery.class});
-
ClassproxyClass=proxyFactory.createClass();
-
IDBQueryjavassistProxy=(IDBQuery)proxyClass.newInstance();
-
((ProxyObject)javassistProxy).setHandler(newJavassistDynDbQueryHandler());
-
returnjavassistProxy;
-
}
-
-
-
-
-
-
-
publicstaticIDBQuerycreateJavassistBytecodeDynamicProxy()throwsException{
-
ClassPoolmPool=newClassPool(true);
-
-
CtClassmCtc=mPool.makeClass(IDBQuery.class.getName()+"JavaassistBytecodeProxy");
-
-
mCtc.addInterface(mPool.get(IDBQuery.class.getName()));
-
-
mCtc.addConstructor(CtNewConstructor.defaultConstructor(mCtc));
-
-
-
mCtc.addField(CtField.make("public"+IDBQuery.class.getName()+"real;",mCtc));
-
StringdbQueryname=DBQuery.class.getName();
-
-
mCtc.addMethod(CtNewMethod.make("publicStringrequest(){if(real==null)real=new"+dbQueryname+"();returnreal.request();}",mCtc));
-
-
-
Classpc=mCtc.toClass();
-
-
IDBQuerybytecodeProxy=(IDBQuery)pc.newInstance();
-
returnbytecodeProxy;
-
}
-
-
}
三种动态代理:JDK动态代理创建速度优于CGLIB动态代理,但是在函数的调用性能上远不如CGLIB和Javassist。故CGLIB和Javassist整体性能上比JDK动态代理好。
性能比较:
-
CreateJDKProxy:13ms
-
CreateCGLIBProxy:217ms
-
CreateJAVAASSISTProxy:99ms
-
CreateJAVAASSISTBytecodeProxy:168ms
-
================
-
RunJDKProxy:2224ms,634,022t/s
-
RunCGLIBProxy:1123ms,1,255,623t/s
-
RunJAVAASSISTProxy:3212ms,438,999t/s
-
RunJAVAASSISTBytecodeProxy:206ms,6,844,977t/s
-
----------------
-
RunJDKProxy:2169ms,650,099t/s
-
RunCGLIBProxy:1059ms,1,331,506t/s
-
RunJAVAASSISTProxy:3328ms,423,697t/s
-
RunJAVAASSISTBytecodeProxy:202ms,6,980,521t/s
-
----------------
-
RunJDKProxy:2174ms,648,604t/s
-
RunCGLIBProxy:1032ms,1,366,342t/s
-
RunJAVAASSISTProxy:3119ms,452,088t/s
-
RunJAVAASSISTBytecodeProxy:207ms,6,811,910t/s
-
----------------
Javassist字节码最快,CGLIB次之,是JDK的两倍。
它们都是通过字节码生成来实现动态代理的。只不过是它们生成的字节码不一样,像JDK,CGLIB都考虑了很多因素,以及继承或包装了自己的一些类,所以生成的字节码非常大,而我们很多时候用不上这些,手工生成的字节码非常小(Javassist是手工生成的字节码),所以速度快。
另外,ASM也是手工生成的字节码,速度也很快,但是它没有一个数量级,通常情况下选用Javassist生成字节码的方式。
分享到:
相关推荐
第二部分对高性能服务器编程的核心要素进行了全面深入的剖析,包含Linux网络编程API、高级I/O函数、Linux服务器程序规范、高性能服务器程序框架、I/O复用、信号、定时器、高性能I/O框架库Libevent、多进程编程、多...
Nginx反向代理服务器及负载均衡服务器配置实战 利用keepalived+Nginx实战Nginx高可用方案 基于Nginx实现访问控制、连接限制 Nginx动静分离实战 Nginx Location ReWrite 等语法配置及原理分析 Nginx提供https...
同时书中还深入剖析了Nginx架构,帮助你深入了解Ngnix原理,以便在面对Nginx问题时,你也可以找到最合适的方法修复或者规避问题。另外,本书还展示了Nginx在服务器开发上的许多巧妙设计,了解这些技巧可以帮助你拓展...
深入剖析ASP.NET组件设计]一书第三章关于ASP.NET运行原理讲述的补白 asp.net 运行机制初探(httpModule加载) 利用反射来查看对象中的私有变量 关于反射中创建类型实例的两种方法 ASP.Net应用程序的多进程模型 NET委托...
SQL Server专家的呕心力作,数据库管理员的实战宝典,全面、深入地剖析SQL Server2008新特性,结构独特,实例丰富,操作性强。 作者简介 作者:(美国)斯坦里克 (William R.Stanek) 译者:贾洪峰 William R.Stanek...
SQL Server专家的呕心力作,数据库管理员的实战宝典,全面、深入地剖析SQL Server2008新特性,结构独特,实例丰富,操作性强。 编辑本段 目录 第Ⅰ部分 SQL Server 2008管理基础 第1章 SQL Server 2008管理...
本书是阿里巴巴资深Nginx技术专家呕心沥血之作,是作者多年的经验结晶,也是目前市场上唯一一本通过还原Nginx设计思想,剖析Nginx架构来帮助读者快速高效开发HTTP模块的图书。本书首先通过介绍官方Nginx的基本用法和...
SQL Server专家的呕心力作,数据库管理员的实战宝典,全面、深入地剖析SQL Server2008新特性,结构独特,实例丰富,操作性强。 作者简介 作者:(美国)斯坦里克 (William R.Stanek) 译者:贾洪峰 William R.Stanek...
SQL Server专家的呕心力作,数据库管理员的实战宝典,全面、深入地剖析SQL Server2008新特性,结构独特,实例丰富,操作性强。 作者简介 作者:(美国)斯坦里克 (William R.Stanek) 译者:贾洪峰 William R.Stanek...
SQL Server专家的呕心力作,数据库管理员的实战宝典,全面、深入地剖析SQL Server2008新特性,结构独特,实例丰富,操作性强。 编辑本段 目录 第Ⅰ部分 SQL Server 2008管理基础 第1章 SQL Server 2008管理...
SQL Server专家的呕心力作,数据库管理员的实战宝典,全面、深入地剖析SQL Server2008新特性,结构独特,实例丰富,操作性强。 编辑本段 目录 第Ⅰ部分 SQL Server 2008管理基础 第1章 SQL Server 2008管理...
SQL Server专家的呕心力作,数据库管理员的实战宝典,全面、深入地剖析SQL Server2008新特性,结构独特,实例丰富,操作性强。 编辑本段 目录 第Ⅰ部分 SQL Server 2008管理基础 第1章 SQL Server 2008管理...
以 Jive 为例,剖析代理模式在用户级别授权机制上的应用 设计模式之 Facade(门面?) 可扩展的使用 JDBC针对不同的数据库编程,Facade提供了一种灵活的实现. 设计模式之 Composite(组合) 就是将类用树形结构组合成...
51AngularJS表单与传统表单的比较139 介绍ngModel指令141 52创建用户信息表单142 53理解输入指令143 添加所需验证143 使用基于文本的输入(text、textarea、e—mail、URL、number)143 使用checkbox输入144 ...
本书主要介绍asp.net的控件开发,书中通过70多个例子讲解了asp.net控件开发技术的各个方面,而且剖析了很多控件中系统基类源代码,读者从这些系统源代码可以体会设计模式思想。如果扎实地掌握了asp.net控件的运行...
网上会展的实施依赖于现代计算机信息技术,由于计算机网络信息的全球性、开放性、扩散性、共享性和动态性等特性,它在存储、处理、使用和传输上存在严重脆弱性,易于受计算机病毒的感染,数据被干扰、遗漏、丢失,...