Java中的Cglib代理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/May_3/article/details/79668996

写在前面:

    首先我们知道动态代理模式是实现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生成的代理类是被代理类的子类。


猜你喜欢

转载自blog.csdn.net/May_3/article/details/79668996
今日推荐