基于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
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();}@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
原创粉丝点击