cglib动态代理实现原理

cglib是一个字节码操纵库,底层基于ASM框架。虽然JDK同样提供了动态代理功能,但是必须将需要代理的方法写在接口中,由主体类继承,很不灵活,而且性能不如cglib。下面是一个使用cglib动态代理的例子。

主体类:

public class MyClass {
public void print() {  
	    System.out.println("I'm in MyClass.print!");  
}  
}

代理类:

public class Main { public static void main(String[] args) {
			System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, System.getProperty("user.dir") + "/bin");
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(MyClass.class);
		enhancer.setCallback(new MethodInterceptorImpl());
		MyClass my = (MyClass) enhancer.create();
		my.print();
	}
  
  private static class MethodInterceptorImpl implements MethodInterceptor {  
	  public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
			// log something
			System.out.println(method + " intercepted!");			
			proxy.invokeSuper(obj, args);
			return null;
		}
	}
}

实现原理:
1.操纵字节码,生成Myclass的子类。将MyClass的子类的字节码反编译之后,看起来会接近这个等价类:
class MyClass$$EnhancerByCGLIB extends MyClass{
	private MethodInterceptor methodInterceptor;
	
	public void print() throws Throwable {
		Class localClass = Class.forName("cgproxy.MyClass$$EnhancerByCGLIB");
	    	ClassLoader classLoader = localClass.getClassLoader();
	    	Method method = Class.forName("cgproxy.MyClass").getDeclaredMethod("print", new Class[0]);
	    	MethodProxy methodProxy = MethodProxy.create(classLoader, method.getDeclaringClass(), localClass, "()V", "print", "CGLIB$print");
		methodInterceptor.intercept(this, method, null, methodProxy);
	}
	
	public void CGLIB$print() {
		super.print();
	}
}
需要注意的是,继承自Object的方法都会按相同的方式生成字节码,wait,notify方法除外,因此MyClass.toString()也会被代理。
这是直接由字节码反编译的结果,可以忽略
public class MyClass$$EnhancerByCGLIB$$1e2eda10 extends MyClass
  implements Factory {
static void CGLIB$STATICHOOK1() {
    	CGLIB$THREAD_CALLBACKS = new ThreadLocal();
    	Class localClass;
    	CGLIB$emptyArgs = new Object[0];
    	ClassLoader tmp27_17 = (localClass = Class.forName("cgproxy.MyClass$$EnhancerByCGLIB$$1e2eda10")).getClassLoader();
    	CGLIB$print$0$0$Proxy = MethodProxy.create(tmp27_17, (1e2eda10.CGLIB$print$0$0$Method = Class.forName("cgproxy.MyClass").getDeclaredMethod("print", new Class[0])).getDeclaringClass(), localClass, "()V", "print", "CGLIB$print$0$0");
    	return;
}
final void CGLIB$print$0$0() {
	super.print();
}
public final void print() {
	MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
	if (tmp4_1 == null)
	{
		tmp4_1;
		CGLIB$BIND_CALLBACKS(this);
	}
	if (this.CGLIB$CALLBACK_0 != null)
		return;
  	super.print();
}}
	









2.执行代码,enhancer.create返回的是MyClass$$EnhancerByCGLIB类的实例,my.print()实际调用的是MyClass$$EnhancerByCGLIB.print(),然后会被MethodInterceptor代理类拦截
3.完成前置代理
4.调用主体类的print()方法:MethodProxy.invokeSuper(MyClass$$EnhancerByCGLIB, Object[]), 这是MethodProxy的相关代码
public class MethodProxy {
	private FastClass f2;
	private int i2;
   	public Object invokeSuper(Object obj, Object[] args) throws Throwable {
         	try {
             		return f2.invoke(i2, obj, args);
        	} catch (InvocationTargetException e) {
             		throw e.getTargetException();
        	}
     }
}
FastClass也是操纵字节码动态生成的类,invoke()会根据事先建立的int值与方法之间的映射,通过int索引访问方法,字节码如下(可能是JD-GUI支持的jdk版本太低了,这一段不能反编译成Java代码)
  public Object invoke(int paramInt, Object paramObject, Object[] paramArrayOfObject)
    throws InvocationTargetException
  {
    // Byte code:
    //   0: aload_2															//load paramObject到oprand stack
    //   1: checkcast 152	cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10								//类型检查
    //   4: iload_1															//load paramInt索引到opran stack
    //   5: tableswitch	default:+387 -> 392, 0:+123->128, 1:+138->143, 2:+142->147, 3:+154->159, 4:+176->181, 5:+186->191, 6:+196->201	//跳转
    //   129: iconst_0
    //   130: aaload
    //   131: invokevirtual 153	cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:equals	(Ljava/lang/Object;)Z
    //   134: new 155	java/lang/Boolean
    //   137: dup_x1
    //   138: swap
    //   139: invokespecial 158	java/lang/Boolean:<init>	(Z)V
    //   142: areturn
    //   143: invokevirtual 159	cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:toString	()Ljava/lang/String;
    //   146: areturn
    //   147: invokevirtual 160	cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:hashCode	()I
    //   150: new 162	java/lang/Integer
    //   153: dup_x1
    //   154: swap
    //   155: invokespecial 165	java/lang/Integer:<init>	(I)V
    //   158: areturn
    //   159: aload_3
    //   160: iconst_0
    //   161: aaload
    //   162: checkcast 167	[Ljava/lang/Class;
    //   165: aload_3
    //   166: iconst_1
    //   167: aaload
    //   168: checkcast 169	[Ljava/lang/Object;
    //   171: aload_3
    //   172: iconst_2
    //   173: aaload
    //   174: checkcast 171	[Lnet/sf/cglib/proxy/Callback;
    //   177: invokevirtual 174	cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:newInstance	([Ljava/lang/Class;[Ljava/lang/Object;[Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;
    //   180: areturn
    //   181: aload_3
    //   182: iconst_0
    //   183: aaload
    //   184: checkcast 176	net/sf/cglib/proxy/Callback
    //   187: invokevirtual 179	cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:newInstance	(Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;
    //   190: areturn
    //   191: aload_3
    //   192: iconst_0
    //   193: aaload
    //   194: checkcast 171	[Lnet/sf/cglib/proxy/Callback;
    //   197: invokevirtual 182	cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:newInstance	([Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;
    //   200: areturn
    //   201: invokevirtual 185	cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:print	()V						//paramObject.print()
    //   204: aconst_null														//将null压入oprand stack
    //   205: areturn															//return
}


  
  



5.方法返回,如果有后置增强的话,进行后置增强

Java字节代码增强(ASM)

JDK动态代理示例

html学得好,博客写到老,各种奇怪的字符都得手动删,囧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值