基于cglib实现的动态代理原理与源码解析
2014-10-06 22:21
786 查看
CGLib介绍:
CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。Hibernate用它来实现PO(Persistent Object 持久化对象)字节码的动态生成。
JDK代理存在的问题分析:
代理为控制要访问的目标对象提供了一种途径。当访问对象时,它引入了一个间接的层。JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理。JDK的动态代理用起来非常简单,但它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的继承的类,该怎么办?现在我们可以使用CGLIB包来实现。
CGLib用途介绍:
CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring
AOP和dynaop,为他们提供方法的interception(拦截)。最流行的OR Mapping工具hibernate也使用CGLIB来代理单端single-ended(多对一和一对一)关联(对集合的延迟抓取,是采用其他机制实现的)。EasyMock和jMock是通过使用模仿(moke)对象来测试java代码的包。它们都通过使用CGLIB来为那些没有接口的类创建模仿(moke)对象。CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。除了CGLIB包,脚本语言例如Groovy和BeanShell,也是使用ASM来生成java的字节码。当然不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
CGLib代码包结构:
core (核心代码)
EmitUtils
ReflectUtils
KeyFactory
ClassEmitter/CodeEmitter
NamingPolicy/DefaultNamingPolicy
GeneratorStrategy/DefaultGeneratorStrategy
DebuggingClassWriter
ClassGenerator/AbstractClassGenerator
beans (bean操作类)
BeanCopier
BulkBean
BeanMap
ImmutableBean
BeanGenerator
reflect
FastClass
proxy
MethodInterceptor , Dispatcher, LazyLoader , ProxyRefDispatcher , NoOp , FixedValue , InvocationHandler(提供和jdk proxy的功能)
Enhancer
CallbackGenerator
Callback
CallbackFilter
util
StringSwitcher
ParallelSorter
transform
CGLib动态代理的实现:
要实现一个对象的动态代理,我们可以这么做:
首先实现一个简单业务类:
客户端测试代码如下:
com.tds.cglib.BusinessObject$$EnhancerByCGLIB$$934b0d42
com.tds.cglib.BusinessObject
事物开始...
方法正在执行...
事物结束...
从运行结果可以看出,新生成的对象确实是原对象类的子类所产生的对象
我们主要关注一个getInstance这个方法,这个方法主要做了三件事:
设置enhancer对象的父类;设置enhancer的回调对象;创建代理对象;
重点是create这个方法,我们看一下create这个方法的源码:
这行代码正是产生代表类的字节码,详细的信息可以通过调试得到
通过上面的分析,可知,本质上,基于cglib实现的动态代理的核心类是Enhancer类,这个类根据传进去的参数来生成新的类的对象
CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。Hibernate用它来实现PO(Persistent Object 持久化对象)字节码的动态生成。
JDK代理存在的问题分析:
代理为控制要访问的目标对象提供了一种途径。当访问对象时,它引入了一个间接的层。JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理。JDK的动态代理用起来非常简单,但它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的继承的类,该怎么办?现在我们可以使用CGLIB包来实现。
CGLib用途介绍:
CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring
AOP和dynaop,为他们提供方法的interception(拦截)。最流行的OR Mapping工具hibernate也使用CGLIB来代理单端single-ended(多对一和一对一)关联(对集合的延迟抓取,是采用其他机制实现的)。EasyMock和jMock是通过使用模仿(moke)对象来测试java代码的包。它们都通过使用CGLIB来为那些没有接口的类创建模仿(moke)对象。CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。除了CGLIB包,脚本语言例如Groovy和BeanShell,也是使用ASM来生成java的字节码。当然不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
CGLib代码包结构:
core (核心代码)
EmitUtils
ReflectUtils
KeyFactory
ClassEmitter/CodeEmitter
NamingPolicy/DefaultNamingPolicy
GeneratorStrategy/DefaultGeneratorStrategy
DebuggingClassWriter
ClassGenerator/AbstractClassGenerator
beans (bean操作类)
BeanCopier
BulkBean
BeanMap
ImmutableBean
BeanGenerator
reflect
FastClass
proxy
MethodInterceptor , Dispatcher, LazyLoader , ProxyRefDispatcher , NoOp , FixedValue , InvocationHandler(提供和jdk proxy的功能)
Enhancer
CallbackGenerator
Callback
CallbackFilter
util
StringSwitcher
ParallelSorter
transform
CGLib动态代理的实现:
要实现一个对象的动态代理,我们可以这么做:
首先实现一个简单业务类:
package com.tds.cglib; public class BusinessObject { public void doSomething() { System.out.println("方法正在执行..."); } }再实现一个实现代理的类:
package com.tds.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class BusinessInterfaceProxy implements MethodInterceptor{ private Object target; public Object getInstance(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("事物开始..."); proxy.invokeSuper(obj, args); System.out.println("事物结束..."); return null; } }这个类是实现cglib动态代理的关键,要实现cglib动态代理,必须要实现MethodInterceptor(方法拦截器接口),这个接口的源码如下:
package net.sf.cglib.proxy; /** * General-purpose {@link Enhancer} callback which provides for "around advice". * @author Juozas Baliuka <a href="mailto:baliuka@mwm.lt">baliuka@mwm.lt</a> * @version $Id: MethodInterceptor.java,v 1.8 2004/06/24 21:15:20 herbyderby Exp $ */ public interface MethodInterceptor extends Callback { /** * All generated proxied methods call this method instead of the original method. * The original method may either be invoked by normal reflection using the Method object, * or by using the MethodProxy (faster). * @param obj "this", the enhanced object * @param method intercepted Method * @param args argument array; primitive types are wrapped * @param proxy used to invoke super (non-intercepted method); may be called * as many times as needed * @throws Throwable any exception may be thrown; if so, super method will not be invoked * @return any value compatible with the signature of the proxied method. Method returning void will ignore this value. * @see MethodProxy */ public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable; }从源码可以看出,这个接口只有一个方法——intercept,这个方法有4个参数,分别是增强的对象,即实现这个接口类的一个对象;method表示要被拦截的方法; args要被拦截方法的参数;proxy表示要触发父类的方法对象;
客户端测试代码如下:
package com.tds.cglib; public class CglibTest { public static void main(String[] args) { BusinessInterfaceProxy cglib = new BusinessInterfaceProxy(); BusinessObject businessObject = (BusinessObject) cglib.getInstance(new BusinessObject()); System.out.println(businessObject.getClass().getName()); System.out.println(businessObject.getClass().getSuperclass().getName()); businessObject.doSomething(); } }运行结果如下:
com.tds.cglib.BusinessObject$$EnhancerByCGLIB$$934b0d42
com.tds.cglib.BusinessObject
事物开始...
方法正在执行...
事物结束...
从运行结果可以看出,新生成的对象确实是原对象类的子类所产生的对象
我们主要关注一个getInstance这个方法,这个方法主要做了三件事:
设置enhancer对象的父类;设置enhancer的回调对象;创建代理对象;
重点是create这个方法,我们看一下create这个方法的源码:
/** * Generate a new class if necessary and uses the specified * callbacks (if any) to create a new object instance. * Uses the no-arg constructor of the superclass. * @return a new instance */ public Object create() { classOnly = false; argumentTypes = null; return createHelper(); }这个方法的大意是这样的:如果有必要,就创建一个新类,并且用指定的回调对象创建一个新的对象实例,使用的父类的参数的构造方法来实例化父类的部分,我们再来分析一下create方法的方法体,前面两行主要是设置classOnly和argumentTypes这两个字段的值,表明要创建的对象不仅仅是一个类,参数类型设置为空,是为了用父类的无参数的构造方法,重点关注createHelper这个方法,源码如下:
private Object createHelper() { validate(); if (superclass != null) { setNamePrefix(superclass.getName()); } else if (interfaces != null) { setNamePrefix(interfaces[ReflectUtils.findPackageProtected(interfaces)].getName()); } return super.create(KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null, ReflectUtils.getNames(interfaces), filter, callbackTypes, useFactory, interceptDuringConstruction, serialVersionUID)); }这个方法首先对要创建的对象作了一个检验,主要是校验classOnly,callbacks,callbackTypes以及interfaces这些参数是否符合要求,如果不符合相关的要求,就会抛出异常,紧接着根据superclass和interfaces这两个参数调生成新类名的前缀,最后到了最重要的方法,就是Enhancer类的父类AbstractClassGenerator的create方法,在调用这个方法之前会调用EnhancerKey接口实现 类的newInstance方法生成的String对象的值为net.sf.cglib.proxy.Enhancer$EnhancerKey,然后AbstractClassGenerator类的create方法根据这个key产生了代理对象,create方法体如下:
protected Object create(Object key) { try { Class gen = null; synchronized (source) { ClassLoader loader = getClassLoader(); Map cache2 = null; cache2 = (Map)source.cache.get(loader); if (cache2 == null) { cache2 = new HashMap(); cache2.put(NAME_KEY, new HashSet()); source.cache.put(loader, cache2); } else if (useCache) { Reference ref = (Reference)cache2.get(key); gen = (Class) (( ref == null ) ? null : ref.get()); } if (gen == null) { Object save = CURRENT.get(); CURRENT.set(this); try { this.key = key; if (attemptLoad) { try { gen = loader.loadClass(getClassName()); } catch (ClassNotFoundException e) { // ignore } } if (gen == null) { byte[] b = strategy.generate(this); String className = ClassNameReader.getClassName(new ClassReader(b)); getClassNameCache(loader).add(className); gen = ReflectUtils.defineClass(className, b, loader); } if (useCache) { cache2.put(key, new WeakReference(gen)); } return firstInstance(gen); } finally { CURRENT.set(save); } } } return firstInstance(gen); } catch (RuntimeException e) { throw e; } catch (Error e) { throw e; } catch (Exception e) { throw new CodeGenerationException(e); } }这个方法中有一个很重要的一行代码:
byte[] b = strategy.generate(this);
这行代码正是产生代表类的字节码,详细的信息可以通过调试得到
通过上面的分析,可知,本质上,基于cglib实现的动态代理的核心类是Enhancer类,这个类根据传进去的参数来生成新的类的对象
相关文章推荐
- Spring AOP源码解析——AOP动态代理原理和实现方式
- 基于jdk动态代理的实现与源码解析
- JDK动态代理的实现和原理解析(基于JDK1.7)
- [读书笔记]深入解析MapReduce架构设计与实现原理——CH4 Java反射机制与动态代理
- 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别。
- JDK动态代理实现原理解析
- CGLib动态代理原理及实现
- 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别
- 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别
- CGLib动态代理原理及实现
- alljoyn:基于java动态代理的RPC实现原理分析
- 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别。
- cglib 动态代理 常用功能 原理及实现
- 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别。
- 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务
- Cglib实现动态代理原理
- CGLib动态代理原理及实现的一个小例子
- cglib源码分析(四):cglib 动态代理原理分析
- 【转载】CGLib动态代理原理及实现
- CGLib动态代理原理及实现