[置頂] 靜態(tài)代理和動(dòng)態(tài)代理
來(lái)源:程序員人生 發(fā)布時(shí)間:2014-11-10 08:34:48 閱讀次數(shù):2532次
所謂的代理設(shè)計(jì)就是指由1個(gè)代理主題來(lái)操作真實(shí)主題,真實(shí)主題履行具體的業(yè)務(wù)操作,而代理主題負(fù)責(zé)其他相干業(yè)務(wù)的處理。
系統(tǒng)中常常有這類需求:在某些操作前需要進(jìn)行驗(yàn)證操作,比如:在添加/刪除操作時(shí),先進(jìn)性用戶信息驗(yàn)證,確認(rèn)該用戶是不是具有這些操作的權(quán)限。代碼以下:
//UserManager接口:
public interface UserManager {
public void addUser(String username, String password);
public void delUser(int userId);
}
//UserManagerImpl類,實(shí)現(xiàn)UserManager 接口:
public class UserManagerImpl implements UserManager {
public void addUser(String username, String password) {
checkSecurity();
System.out.println("---------UserManagerImpl.add()--------");
}
public void delUser(int userId) {
checkSecurity();
System.out.println("---------UserManagerImpl.delUser()--------");
}
private void checkSecurity() {
System.out.println("-------checkSecurity-------");
}
}
在添加/刪除方法中,加入驗(yàn)證函數(shù)checkSecurity(),那末問(wèn)題來(lái)了,如果上百個(gè)函數(shù)中都需要加驗(yàn)證函數(shù)checkSecurity(),那末就要寫上百個(gè)checkSecurity()函數(shù),如果哪天需求變化了,不需要進(jìn)行用戶驗(yàn)證了,那末就需要在上百個(gè)函數(shù)中刪除checkSecurity(),保護(hù)性極差。如何解決此問(wèn)題?
1,靜態(tài)代理
添加代理類
public class UserManagerImpl implements UserManager {
public void addUser(String username, String password) {
//checkSecurity();
System.out.println("---------UserManagerImpl.add()--------");
}
public void delUser(int userId) {
//checkSecurity();
System.out.println("---------UserManagerImpl.delUser()--------");
}
// private void checkSecurity() {
// System.out.println("-------checkSecurity-------");
// }
}
//UserManagerImplProxy代理類:(注:該代理類只能為UserManager接口服務(wù))
public class UserManagerImplProxy implements UserManager {
private UserManager userManager;
public UserManagerImplProxy(UserManager userManager) {
this.userManager = userManager;
}
public void addUser(String username, String password) {
checkSecurity();
userManager.addUser(username, password);
}
public void delUser(int userId) {
checkSecurity();
userManager.delUser(userId);
}
private void checkSecurity() {
System.out.println("-------checkSecurity-------");
}
}
靜態(tài)代理:
代理類――編譯時(shí)創(chuàng)建,UserManagerImplProxy只能為UserManager接口服務(wù);
通過(guò)代理類來(lái)進(jìn)行添加/刪除操作,這樣就能夠確保目標(biāo)函數(shù)不被改變,可保護(hù)性增強(qiáng),但是沒(méi)有解決根本問(wèn)題,由于這樣1來(lái)把問(wèn)題轉(zhuǎn)移給了代理類,上述講到的問(wèn)題仍然存在。如何解決?
2,動(dòng)態(tài)代理:
將共有驗(yàn)證checkSecurity()拿出來(lái),放在單獨(dú)類中;
代理類――運(yùn)行時(shí)創(chuàng)建,可以為各個(gè)接口服務(wù);
動(dòng)態(tài)代理斟酌的問(wèn)題:把遍及在系統(tǒng)里的獨(dú)立服務(wù)(具有橫切性的服務(wù))拿出來(lái)放在1個(gè)地方,運(yùn)行時(shí)自動(dòng)放入;斟酌的是橫向問(wèn)題;
代碼:
//UserManager接口
public interface UserManager {
public void addUser(String username, String password);
public void delUser(int userId);
}
//UserManagerImpl類 實(shí)現(xiàn)UserManager接口
public class UserManagerImpl implements UserManager {
public void addUser(String username, String password) {
//checkSecurity();
System.out.println("---------UserManagerImpl.add()--------");
}
public void delUser(int userId) {
//checkSecurity();
System.out.println("---------UserManagerImpl.delUser()--------");
}
// private void checkSecurity() {
// System.out.println("-------checkSecurity-------");
// }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//需要實(shí)現(xiàn)接口InvocationHandler
public class SecurityHandler implements InvocationHandler {
private Object targetObject;//目標(biāo)類,根據(jù)目標(biāo)創(chuàng)建代理類
//創(chuàng)建代理類
public Object createProxyInstance(Object targetObject) {
this.targetObject = targetObject;
//根據(jù)目標(biāo)生成代理
//參數(shù):第1個(gè)參數(shù):代理類 裝載代理類;第2個(gè)參數(shù):目標(biāo)接口;第3個(gè)參數(shù):
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),
this);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
checkSecurity();
//調(diào)用目標(biāo)方法
Object ret = method.invoke(targetObject, args);
return ret;
}
private void checkSecurity() {
System.out.println("-------checkSecurity-------");
}
}
//客戶端
public class Client {
public static void main(String[] args) {
SecurityHandler hander = new SecurityHandler();
//生成代理
UserManager userManager = (UserManager)hander.createProxyInstance(new UserManagerImpl());
userManager.addUser("張3", "123");//調(diào)用ddUser()方法
}
}
3,總結(jié)
靜態(tài)代理通常只代理1個(gè)類,動(dòng)態(tài)代理是代理1個(gè)接口下的多個(gè)實(shí)現(xiàn)類。
靜態(tài)代理事前知道要代理的是甚么,而動(dòng)態(tài)代理不知道要代理甚么東西,只有在運(yùn)行時(shí)才知道。
動(dòng)態(tài)代理是實(shí)現(xiàn)JDK里的InvocationHandler接口的invoke方法,但注意的是代理的是接口,也就是你的業(yè)務(wù)類必須要實(shí)現(xiàn)接口,通過(guò)Proxy里的newProxyInstance得到代理對(duì)象。
還有1種動(dòng)態(tài)代理CGLIB,代理的是類,不需要業(yè)務(wù)類繼承接口,通過(guò)派生的子類來(lái)實(shí)現(xiàn)代理。通過(guò)在運(yùn)行時(shí),動(dòng)態(tài)修改字節(jié)碼到達(dá)修改類的目的。
生活不易,碼農(nóng)辛苦
如果您覺(jué)得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)