基于cglib实现的动态代理原理与源码解析
来源:互联网 发布:制作试卷的软件 编辑:程序博客网 时间:2024/06/05 03:00
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
要实现一个对象的动态代理,我们可以这么做:
首先实现一个简单业务类:
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();}@Overridepublic 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类,这个类根据传进去的参数来生成新的类的对象
0 0
- 基于cglib实现的动态代理原理与源码解析
- 基于jdk动态代理的实现与源码解析
- 设计模式--CGLib动态代理的实现与解析
- cglib动态代理[基于类操作的动态代理实现]
- Cglib实现动态代理原理
- Cglib实现动态代理原理
- cglib动态代理实现原理
- 基于cglib的动态代理
- Java 动态代理的理解与Cglib动态代理实现
- Cglib动态代理源码例子解析
- Spring学习笔记--AOP的简略实现(基于J2SE动态代理与CgLib)
- 基于jdk和cglib实现的动态代理
- SpringAOP的CGLIB动态代理的底层原理实现
- CGLib动态代理原理及实现的一个小例子
- CGLIB 动态代理的实现
- CGLib动态代理原理及实现
- CGLib动态代理原理及实现
- CGLib动态代理原理及实现
- 关于winodws中的hiberfil.sys文件
- android开发学习(三)——sharedPreference,xml文件序列化和反序列
- Nixie:戴在腕上的四轴「摄影师」
- lowlevel_init.S 较详细分析
- Redis源码分析(二)--结构体分析(1)
- 基于cglib实现的动态代理原理与源码解析
- 毯遣俣竞业戮奄俣寄滥负惫康腊必
- NSAssertionHandler类
- linkin大话设计模式--观察者模式
- 背包问题九讲笔记_01背包
- Linux - 进程控制 代码(C)
- 腾讯与唯品会笔试面试经历
- 哈希排序
- 【从0开始学香蕉派】序列之11:samba服务器和香蕉派的那些勾当