CGLIB动态代理

要理解CGLIB动态代理首先要知道如何使用CGLIB动态代理。为了更好说明动态代理。先来看一个简单的CGLIB动态代理示例。先定义一个被代理类。为了说明问题此处这个被代理的类只有一个简单的方法。在控制台上打印一个hello字符串。

package com.proxy.cglib;

public class Demo {
	public void sayHello(){
		System.out.println("hello");
	}
}

针对这被代理类我们定义一个方法拦截器Interceptor。拦截器实现了MethodInterceptor接口并且重写了interceptor方法。再该方法中我们在被代理类方法调用前后添加了通用的业务代码。这里我在被调用方法前后打印了befor和after。同时为了主函数代码看起来简单这里将获取代理对象的方法定义在该拦截器中。

package com.proxy.cglib;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class Interceptor implements MethodInterceptor{

	public Object intercept(Object proxy, Method method, Object[] args, MethodProxy proxyMethod) throws Throwable {
		System.out.println("befor");
		Object obj=proxyMethod.invokeSuper(proxy, args);
		System.out.println("after");
		return obj;
	}
	
	public Object getProxy(Class cls){
		//实例化一个增强器,也就是cglib中的一个class generator
		Enhancer eh = new Enhancer();
		//设置目标类
		eh.setSuperclass(cls);
		// 设置拦截对象
		eh.setCallbacks(new Callback[]{ this });
		// 生成代理类并返回一个实例
		return eh.create(); 
	}

}

最后通过创建一个主函数来运行这个示例。这个示例逻辑首先定义一个系统变量DebuggingClassWriter.DEBUG_LOCATION_PROPERTY定义了这个系统变量会将代理类持久化到磁盘上面。然后创建一个拦截器interceptor。通过拦截器的getProxy方法创建一个代理对象。该对象代理Demo相关方法。最后调用sayHello方法。

package com.proxy.cglib;

import net.sf.cglib.core.DebuggingClassWriter;

public class Main {
	public static void main(String[] args){
		System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, 
				"F:\\Eclipse1.8\\Learn\\proxy\\target\\classes\\com\\proxy\\cglib");
		Interceptor interceptor=new Interceptor();
		Demo demo=(Demo)interceptor.getProxy(Demo.class);
		demo.sayHello();
	}
}

运行结果如下满足预期。说明上面的Demo类被成功代理。

befor
hello
after

通过上面的示例代码可以很容易想到。要理解CGLIB代理原理。需要明白两个问题。

1.代理对象方法调用如何被转换到拦截器的intercept方法中去的。

2.理解proxyMethod.invokeSuper(proxy, args)是如何调用。

对于第一个问题。为了将代理方法的调用转换成为拦截器的intercept方法调用CGLIB使用了asm字节码技术。根据传入的superClass作为模版用字节码技术创造了一个代理类。通过遍历superClass的方法字段信息重写了代理类。代理类将方法调用委托給拦截器对象。所以代理类的方法调用就被转发到intercept方法中。

对于第二个问题。首先要说明的是proxyMethod.invokeSuper方法调用这个不是一个反射调用。该方法调用采用了FastClass机制。该机制实现的原理是通过方法签名生成hashCode值。根据hashCode的值建立被代理方法的索引。通过索引直接调用被代理的方法。这种机制避免了反射调用。据说效率较高。

因为时间原因没有说的很清除。后续会继续更新

JDK动态代理原理

 

 

你可能感兴趣的:(CGLIB动态代理)