您的位置:首页 > 其它

基于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动态代理的实现:

要实现一个对象的动态代理,我们可以这么做:

首先实现一个简单业务类:

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类,这个类根据传进去的参数来生成新的类的对象
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: