一、CGLib 简单介绍

CGLib (Code Generation Library) 是一个强大的,高性能,高质量的Code生成类库。

它能够在执行期扩展Java类与实现Java接口。

Hibernate用它来实现PO字节码的动态生成。CGLib比 Java 的 java.lang.reflect.Proxy 类更强的在于它不仅能够接管接口类的方法。还能够接管普通类的方法。

CGLib 的底层是Java字节码操作框架 —— ASM。

CGLib就是封装了ASM,简化了ASM的操作,实现了在执行期动态生成新的class。ASM是直接生成class类的方式。不会有性能问题(相对来说)

二、JDK的动态代理 (VS) CGLib

1、实现原理

JDK的动态代理——依据java的反射机制动态生成

利用反射。获取托付类的类载入器。托付类的全部接口,实例化代理类。

通过反射类Proxy以及InvationHandler回调接口实现的。可是动态代理类仅仅能对该类所实现的接口中的方法进行代理。

具有一定的局限性,而且反射的效率也不是非常高。

Proxy 毕竟是通过反射实现的,必须在效率上付出代价:有实验数据表明,调用反射比一般的函数开销至少要大 10 倍。

从程序实现上能够看出,对 proxyclass 的全部方法调用都要通过使用反射的 invoke 方法。

因此。对于性能关键的应用。使用 proxy class是须要精心考虑的。以避免反射成为整个应用的瓶颈。

CGLib ——利用ASM生成字节码原理。利用增强类,创建代理类

CGLib底层採用ASM字节码生成框架。使用字节码技术生成代理类。比反射效率要高。

可是须要主要注意的,CGLib不能对声明为final的方法进行代理。

由于CGLib原理是动态的生成被代理类的子类。

ASM可以通过改造既有类,直接生成须要的代码。

增强的代码是硬编码在新生成的类文件内部的,没有反射带来性能上的付出。它是一个普通的 Java 类而不是 proxy类,甚至可以在应用程序的类框架中拥有自己的位置,派生自己的子类。

在调用目标方法的时候,CGLib会回调MethodInterceptor接口方法拦截。来实现你自己的代理逻辑,类似于JDK中的InvocationHandler接口

2、代码实现

JDK动态代理

package DynamicProxy2upgrade;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; /**
* @ClassName: DynamicProxy
* @Description: 动态代理类。在这里做了一个升级。把代理绑定真实类的关系。Proxy生成实例的代码移到了动态代理这里
* @author 张薄- huaxiangniaoyu0109@126.com
* @date 2015年5月29日 下午9:21:19
*/
public class DynamicProxy implements InvocationHandler { private Object obj ; //托付类,真实类 DynamicProxy(Object obj){
this.obj=obj;
} //绑定代理与托付类。生成新的代理类
public Object bindProxy(Object obj){ //返回一个指定接口的代理类实例,该接口能够将方法调用指派到指定的调用处理程序,如ProxyHandler
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
} @Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return method.invoke(obj, args); //普通的java反射代码,通过反射运行某个类的方法(invoke方法内部实现预处理,对托付类方法调用,事后处理等逻辑。)
} }

JDK动态代理执行结果:‘

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2Fvemhhbmd5aW5nZmVpMDEwOQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">



CGLib动态代理

package CGLibDynamicProxy;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer; //一个字节码增强类,它能够方便的对你想要处理的类进行扩展
import net.sf.cglib.proxy.MethodInterceptor; //方法拦截器
import net.sf.cglib.proxy.MethodProxy; //代理类。JDK的java.long.reflect.Method类的代理类,能够方便的实现对源对象方法的调用(如invokeSuper)
/**
* @ClassName: DynamicProxybyCGLib
* @Description: 基于CGLib的动态代理
* @author 张薄- huaxiangniaoyu0109@126.com
* @date 2015年5月31日 上午8:44:19
*/
public class DynamicProxybyCGLib implements MethodInterceptor { private Object obj; //托付类
public Object getInstance(Object obj){
this.obj = obj;
Enhancer enhancer = new Enhancer(); //增强类
//不同于JDK的动态代理。它不能在创建代理时传obj对 象,obj对象必须被CGLIB包来创建
enhancer.setSuperclass(this.obj.getClass()); //设置被代理类字节码(obj将被代理类设置成父类;作为产生的代理的父类传进来的)。CGLIB依据字节码生成被代理类的子类
enhancer.setCallback(this); //设置回调函数,即一个方法拦截
return enhancer.create(); //创建代理类
} @Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
System.out.println("obj:" + obj.getClass().getName()); //由CGLib动态生成的代理类实例
System.out.println("method:" + method.getName()); //上文中实体类所调用的被代理的方法引用
System.out.println("methodProxy:" + methodProxy.getClass().getName()); //生成的代理类对方法的代理引用
System.out.println("args:"+ args); //參数值列表 Object object = methodProxy.invokeSuper(obj, args); //调用代理类实例上的methodProxy方法的父类方法(即实体类RealSubject中的相应方法) return object;
} }

CGLib动态代理执行结果:

三、小结

CGLib实现的原理,非常详细的原理可能我还是不太懂。可是,大概知道一个过程,首先依据Enhancer创建代理类,怎样创建的呢?依据方法setSuperclass将被代理类作为父类引入。再依据CGLib生成被代理类的子类。依据方法setCallback,回调函数(这里我们的动态代理类实现MethodInterceptor拦截器,依据拦截器的方法intercept,调用代理类的父类方法。实现了代理被代理类的方法的目的),实现方法拦截。最后用create方法创建代理类。

既然口述了CGLib的实现原理,那就再来说说JDK的动态代理吧。依据Proxy的方法newProxyInstance方法创建代理类。该方法里面的參数,分别获取了被代理类的类载入器(用于动态载入),被代理类的全部接口类(以便于实现接口类的全部方法),再通过动态代理类实现InvationHandler。实现接口方法invoke。回调函数(通过反射运行被代理类的方法),这样在实例化动态代理类的时候,就真正的创建了动态代理。

啰里啰嗦的说了这么多,收获还是有的。说出我的心得,假设大家有不同的想法,欢迎拍砖哈。

比方,CGLib的动态代理类。原理是继承,生成了被代理类的子类;而JDK的动态代理类。原理是反射,生成的代理类。实际不具备被代理类内部的方法,每一次调用都须要利用反射。调用被代理类的方法;再来看静态代理,代理类就是通过调用被代理类的方法进行执行的,而它自己本身并不详细被代理类的方法,JDK的动态代理的进步在于。利用反射,将类的载入延迟到程序执行中,解耦了代理类与被代理的关系。

CGLib与JDK的动态代理的更多相关文章

  1. CGLIB 和 JDK生成动态代理类的区别(转)

    文章转自http://luyuanliang.iteye.com/blog/1137292 AOP 使用的设计模式就是代理模式,是对IOC设计的补充.为了扩展性,往往会加上反射,动态生成字节码,生成代 ...

  2. JDK 原生动态代理是怎么实现的 + 面试题

    JDK 原生动态代理是怎么实现的 + 面试题 反射 反射机制是 Java 语言提供的一种基础功能,赋予程序在运行时自省(introspect)的能力.简单来说就是通过反射,可以在运行期间获取.检测和调 ...

  3. 动态代理:JDK原生动态代理(Java Proxy)和CGLIB动态代理原理+附静态态代理

    本文只是对原文的梳理总结,以及自行理解.自己总结的比较简单,而且不深入,不如直接看原文.不过自己梳理一遍更有助于理解. 详细可参考原文:http://www.cnblogs.com/Carpenter ...

  4. JAVA JDK的动态代理反射实现

    动态代理类使用到了一个接口InvocationHandler和一个代理类Proxy ,这两个类配合使用实现了动态代理的功能. 什么是动态代理呢?  普通代理类是指: 给每个具体类写一个代理类,以后要使 ...

  5. 基于 JDK 的动态代理机制

    『动态代理』其实源于设计模式中的代理模式,而代理模式就是使用代理对象完成用户请求,屏蔽用户对真实对象的访问. 举个最简单的例子,比如我们想要「FQ」访问国外网站,因为我们并没有墙掉所有国外的 IP,所 ...

  6. JDK的动态代理深入解析(Proxy,InvocationHandler)(转)

    JDK的动态代理深入解析(Proxy,InvocationHandler)(转) 一.什么是动态代理 动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实.代理一般会实现它所表示的实际对象的 ...

  7. jdk的动态代理

    至于jdk的动态代理怎么用此处并不多说,现在是更深一步的理解,jdk的Proxy类到底做了什么. Proxy.newProxyInstance可以生成代理类,此方法有三个参数(ClassLoader ...

  8. JDK的动态代理-----为接口进行代理

    JDK的动态代理是必须掌握的,动态代理的好处就不用我多说了吧 :) 小弟最近在研究mybatis的源码实现,就开始了解mybatis的Mapper代理机制,为什么接口不用实现类也能代理? 好了,废话不 ...

  9. JDK的动态代理机制

    JDK Proxy OverView jdk的动态代理是基于接口的,必须实现了某一个或多个随意接口才干够被代理,并且仅仅有这些接口中的方法会被代理.看了一下jdk带的动态代理api.发现没有样例实在是 ...

随机推荐

  1. hdu 4704(费马小定理+快速幂取模)

    Sum                                                                                Time Limit: 2000/ ...

  2. bzoj 2252 [ 2010 Beijing wc ] 矩阵距离 —— 多源bfs

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2252 又没能自己想出来... 一直在想如何从每个1开始广搜更新答案,再剪剪枝,什么遇到1就不 ...

  3. 89. Ext.Button 按钮

    转自:http://www.cnblogs.com/lipan/archive/2011/12/13/2274797.html 从本篇开始讲基础控件,ExtJs对所有的UI控件都有它自己的一套封装.本 ...

  4. mysql数据库的介绍及安装

    一.什么是数据库 1.什么是数据(Data) 描述事物的符号记录成为数据,描述事物的符号既可以是文字.图片.图像.声音.语言等,数据有多种表现形式,他们都可以经过数字化后存入计算机 在计算机中描述一个 ...

  5. ReferenceEquals()、static Equals() 、instance Equals() 与 operator==之间的联系与区别

    当你创建一个用户自定义类型(类或结构)时,你需要给你的类型定义相等操作.C#中提供了几个不同的函数来验证两个对象是否满足“相等”的含义.public static bool ReferenceEqua ...

  6. dubbo之事件通知

    事件通知 在调用之前.调用之后.出现异常时,会触发 oninvoke.onreturn.onthrow 三个事件,可以配置当事件发生时,通知哪个类的哪个方法 1. 服务提供者与消费者共享服务接口 in ...

  7. react基础篇六

    创建 Refs 使用 React.createRef() 创建 refs,通过 ref 属性来获得 React 元素.当构造组件时,refs 通常被赋值给实例的一个属性,这样你可以在组件中任意一处使用 ...

  8. (转)OL记载Arcgis Server切片

    http://blog.csdn.net/gisshixisheng/article/details/47955787 概述: 本文讲述如何在OpenLayers中调用Arcgis Server切片并 ...

  9. openstack--rabbitmq

    一.MQ 全称为 Message Queue, 消息队列( MQ ) 是一种应用程序对应用程序的通信方法.应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们. 消息传 ...

  10. 团体程序设计天梯赛-练习集-L1-032. Left-pad

    L1-032. Left-pad 根据新浪微博上的消息,有一位开发者不满NPM(Node Package Manager)的做法,收回了自己的开源代码,其中包括一个叫left-pad的模块,就是这个模 ...