基于cglib实现的动态代理原理与源码解析

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();
	}
	
	@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:[email protected]">[email protected]</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实现的动态代理原理与源码解析_第1张图片
通过上面的分析,可知,本质上,基于cglib实现的动态代理的核心类是Enhancer类,这个类根据传进去的参数来生成新的类的对象


你可能感兴趣的:(基于cglib实现的动态代理原理与源码解析)