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