您的位置:首页 > 编程语言 > Java开发

Java中的Cglib代理

2018-03-23 19:04 162 查看
写在前面:
    首先我们知道动态代理模式是实现AOP编程的核心,而动态代理这种设计模式又分为JDK代理和Cglib代理,在上一篇博客中,已经总结了JDK代理的实现过程(https://blog.csdn.net/may_3/article/details/79595432)。这篇博客,我们将总结Cglib代理,以及,这两种代理方式的区别,特点。

    Cglib代理采用了asm框架的字节码技术。通过字节码技术为一个类创建一个子类。并且,在子类中采用方法拦截的技术,拦截所有父类方法的调用。

    Cglib源码分析:

    由于Cglib是第三方的API,所以需要导入相应的Jar包,因为自己是在学习Spring的时候,学习的Cglib代理,所以导入了Spring的核心jar文件,也就包括了Cglib代理的相关Jar文件。import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;    Enhancer、MethodInterceptor、MethodProxy这三个类和接口是我们实现Cglib动态代理的核心。

    首先Enhancer类用于创建代理实例。负责整个代理对象的生命周期。
    其中setSuperclass方法用于设置被代理对象。也就是代理对象的父类。public void setSuperclass(Class superclass)
{
if ((superclass != null) && (superclass.isInterface())) {
setInterfaces(new Class[] { superclass });
} else if ((superclass != null) && (superclass.equals(Object.class))) {
this.superclass = null;
} else {
this.superclass = superclass;
}
}
    setCallback方法用于设置回调。也就是对我们代理的方法转发到这个回调上。且所有回调类必须实现MethodInterceptor接口,并且实现intercept方法。在intercept方法中,传递了4个参数:
(1)Object obj :被代理的源对象
(2)Method method :被代理的对象调用的方法
(3)Object [] args:被调用方法的参数集合
(4)MethodProxy proxy:被调用方法的代理,可以和method完成相同的事情,但是由于内部使用了FastClass机制,而不是反射,所以效率更高。

FastClass机制:
//fastclassinfo类
private static class FastClassInfo
{
FastClass f1;
FastClass f2;
int i1;
int i2;

private FastClassInfo() {}

FastClassInfo(MethodProxy.1 x0)
{
this();
}
}

public Object invokeSuper(Object obj, Object[] args)
throws Throwable
{
try
{
init();
FastClassInfo fci = this.fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
}
catch (InvocationTargetException e)
{
throw e.getTargetException();
}
}
    在FastClassInfo类中,有4个参数f1表示被代理对象,f2表示代理对象,i1,i2是代理类中该方法的两个索引。而对于调用每一个代理方法的请求,都会转发到invokeSuper方法中。通过Hash索引的方式,找到方法,并调用方法,完成代理。

最后一步是调用create方法:
public Object create()
{
this.classOnly = false;
this.argumentTypes = null;
return createHelper();
}
private Object createHelper()
{
validate();
if (this.superclass != null) {
setNamePrefix(this.superclass.getName());
} else if (this.interfaces != null) {
setNamePrefix(this.interfaces[ReflectUtils.findPackageProtected(this.interfaces)].getName());
}
return super.create(KEY_FACTORY.newInstance(this.superclass != null ? this.superclass.getName() : null, ReflectUtils.getNames(this.interfaces), this.filter, this.callbackTypes, this.useFactory, this.interceptDuringConstruction, this.serialVersionUID));
}

Cglib实现动态代理的案例:

代理对象类:package cglib;

public class UserDao {

public void save() {
System.out.println("-----使用Cglib代理------");
}
}
Cglib代理核心类:package cglib;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class ProxyFactory implements MethodInterceptor {
public ProxyFactory(Object target) {
this.target = target;
}

// 维护一个目标对象,即被代理对象
private Object target;

// 为目标对象创建代理对象
public Object getProxyInstance() {
// 工具类
Enhancer en = new Enhancer();
// 设置父类
en.setSuperclass(target.getClass());
// 设置回调函数
en.setCallback(this);
// 创建子类
return en.create();
}

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;
}

}
调试:package cglib;

public class APP {

public static void main(String[] args) {
//目标对象
UserDao target=new UserDao();
System.out.println(target.getClass());
//代理对象
UserDao proxy=(UserDao) new ProxyFactory(target).getProxyInstance();
System.out.println(proxy.getClass());
proxy.save();

}

}

控制台输出:class cglib.UserDao
class cglib.UserDao$$EnhancerByCGLIB$$b5599079
开启事务
-----使用Cglib代理------
提交事务
这样我们就实现了Cglib代理。最后,再来看一下,JDK代理和Cglib代理的对比:
(1)JDK代理只能代理实现接口的类(因为生成的代理类的父类是Proxy类),而Cglib代理未接口的类。
(2)JDK代理使用反射机制,而Cglib使用ASM字节码生成框架,从效率上看,Cglib效率更高。
(3)Cglib不能对声明为final的方法进行代理,因为Cglib生成的代理类是被代理类的子类。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Cglib JDK 动态代理