少年阿宾

那些青春的岁月

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  500 Posts :: 0 Stories :: 135 Comments :: 0 Trackbacks

java动态代理和cglib动态代理在工作中用代理的地方非常多,但一直还没仔细来看代理的原理,今天被同事提到,所以自己开始仔细研究了一下这两者代理都做了些什么工作,并通过编写测试用例的方式来对两种代理原理作理解。
在自行看代码之前,初步问了一下朋友,大概解释这两者区别是,java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。这是朋友说的,我并没自己实验过,所以也没映象,所以开始自己动手实践之:
java动态代理

使用方法:

接口:

public interface Call {
void doCall(String doCall);
}

public interface Processor {
void doProcess(String doProcess);
}

实现类:

public class ServiceImpl implements Call, Processor {

public void doCall(String doCall) {
System.out.println("doCall");
}

public void doProcess(String doProcess) {
System.out.println("doProcess");
}
}

具体代理Handler:

public class ServiceHandler implements InvocationHandler {

private Call callService;

public ServiceHandler(Call callService) {
this.callService = callService;
}

public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("proxyMethod=" + method.getName());
Object obj = method.invoke(this.callService, args);
System.out.println("after invoke!");
return obj;
}

}

使用java动态代理:

public class JdkProxyTest {   
@Test
public void testJdkProxy() {
Call call = new ServiceImpl();
ServiceHandler handler = new ServiceHandler(call);
Call callProxy = (Call) Proxy.newProxyInstance(call.getClass().getClassLoader(),
new Class[]{Call.class}, handler);
callProxy.doCall("test");
}
}

最终效果就是执行代理接口的doCall方法之前,该方法被ServiceHandler给处理了。

通过查看java.lang.reflect.Proxy代码,大致拟了一下它的实现原理:
1. 取到new Class[]{Call.class}这里所有接口,通过Class.forName把接口类加载到JVM,放到内部Set里保存,把接口的完善名字保存,带包名的接口名字,并以把这组接口名称数组转换成List作为key,用于下面生成代理类后保存到内部Map的key.也就是相当于这一组的接口名称对应的一个生成的代理类
2. 主要是从内存里找是否之前已经生成好了这同一组接口的代理类,如果有就直接拿出。这里第一次是需要新建立的,所以开始创建代理,首先检查代理目标接口的访问控制符是否是默认包级别的,如果是就需要给生成的代理类设置目标接口同样的包名,才能默认访问这种级别下的接口。如果这种有默认访问控制标识符的目标接口,又有不同包名的目标接口,则会报出错误。否则其它情况,是给的无包名的代理类,生成的代理类的默认名称是$Proxy开头加Proxy里标识唯一类名的数字,是静态long型变量,每次生成一次代理类会累加
3. 调用ProxyGenerator.generateProxyClass(proxyName, interfaces)动态生成class字节码类,该类相当于是Proxy的子类,实现了需要代理的接口方法,并在每个方法里调用了InvocationHandler的invoke方法,而我们自己实现的InvocationHandler接口类里完成了以反射方式最终对目标业务类的接口方法进行调用。所以此种方式实现的动态代理只能代理接口方法,对具体类的代理不能实现。

 

http://hi.baidu.com/dobug/blog/item/493f817e802479340cd7dab9.html

posted on 2012-06-07 21:51 abin 阅读(690) 评论(0)  编辑  收藏 所属分类: java基础知识

只有注册用户登录后才能发表评论。


网站导航: