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