動態(tài)代理的特點(diǎn)是,不要靜態(tài)的寫Proxy類,而是在運(yùn)行時由jdk自己幫助生成類,然后注入到classloader中去。
代碼:
public interface BusinessProcess{
void processBusiness();
}
public class BusinessProcessImpl implements BusinessProcess{
public void processBusiness(){
System.out.println("in businessProcessImpl");
}
}
如果要對BusinessProcessImpl增加權(quán)限驗(yàn)證功能,那么靜態(tài)代理代碼:
public class BusinessProcessProxy implements BusinessProcess{
private BusinessProcess target;
public BusinessProcessProxy(BusinessProcess target){
this.target = target;
}
public void processBusiness(){
checkPermission();
this.target.processBusiness();
}
}
對于動態(tài)代理:
public class PermissionHandler implements InvocationHandler {
private Object target;
public LoggerHandler(Object target){
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
checkPermission();
Object result = method.invoke(this.target,args);
return result;
}
}
測試代碼:
BusinessProcessImpl impl = new BusinessProcessImpl();
PermissionHandler handler = new PermissionHandler (impl);
BusinessProcess proxy = (BusinessProcess)Proxy.newProxyInstance(impl.getClass().getClassLoader(),impl.getClass().getInterfaces(), handler);
proxy.processBusiness();
注意:
proxy對象是BusinessProcess接口的一個實(shí)現(xiàn)類,但是不是BusinessProcessImpl的子類
看起來好像靜態(tài)代理和動態(tài)代理沒什么區(qū)別,但是仔細(xì)一看,靜態(tài)代理代理的target只能是BusinessProcess對象,而動態(tài)代理卻能夠代理任何一個Object對象,這就是關(guān)鍵區(qū)別。所以程序中不需要為每個核心類寫一個Proxy,而公用一個就可以。
動態(tài)代理的實(shí)現(xiàn)原理:
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);
proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0,proxyClassFile.length);
這是java.lang.reflect.Proxy的兩行關(guān)鍵代碼,第一行代碼生成名為proxyName, 實(shí)現(xiàn)的接口為interfaces的一個類的字節(jié)碼。
第二行代碼,將生成的字節(jié)碼注入到classloader中去。
第一次為某個object生成proxyClass可能比較耗費(fèi)性能,但是Proxy方法作了緩存,可以彌補(bǔ)這一點(diǎn)。此外,動態(tài)代理只能夠?qū)nterfaces進(jìn)行動態(tài)的代理, 也就是說它先找出需要代理的對象實(shí)現(xiàn)的所有的interface, 然后只對所有的這些interface的所有的方法代理,對象除了interfaces以外的方法不予處理。