首先,明確一點:代理不會改變之前寫的所有代碼,代理需要繼承相同的接口。
那麼問題來了,爲什麼要用到代理?
假設有一個接口 UserManager, 這個接口中有很多待實現的方法,此時,有一個實現類實現了這個接口 UserManagetImpl, 並且已經上線,客戶已經在使用了,所以講道理來說,不管是接口或者實現類,都必須做到對修改關閉,對擴展開放。
此時,有一個問題,如果我們需要給接口中每一個方法的實現類的具體實現語句中,加入別的邏輯,比如增加安全性檢查,或者增加事務和日誌,則按照最簡單的寫法是,修改實現類 UserManagerImpl 的每一個方法,加上相應的語句即可。但是,這種做法違背了上面說的 對修改關閉 原則。
於是,出現了代理,這裏的代理指的是靜態代理。
// 接口 UserManager.java
public interface UserManager {
public boolean addUser(String username, String password);
public void delUser(int userId);
public String findUserById(int userId);
public void modifyUser(int userId, String username, String password);
}
// 接口的實現類 UserManagerImpl.java
public class UserManagerImpl implements UserManager {
@Override
public boolean addUser(String username, String password) {
System.out.println("------UserManagerImpl.addUser-----");
return true;
}
@Override
public void delUser(int userId) {
System.out.println("------UserManagerImpl.delUser-----");
}
@Override
public String findUserById(int userId) {
System.out.println("------UserManagerImpl.findUserById-----");
return "zhangsan";
}
@Override
public void modifyUser(int userId,String username, String password) {
System.out.println("------UserManagerImpl.modifyUser-----");
}
@Override
public void checkSecurity() {
System.out.println("------UserManagerImpl.checkSecurity-----");
}
}
//靜態代理,需要實現同樣的接口
//代理不會改變之前的代碼,對修改關閉
//將實際的實現通過構造器傳遞到代理中,通過代理調用實際實現類中的具體實現方法
public class UserManagerProxy implements UserManager {
private UserNamager userManager;
public UserManagerProxy(UserNamager userManager) {
this.userManager = userManager;
}
@Override
public boolean addUser(String username, String password) {
checkSecurity();
userManager.addUser(username,password);
return true;
}
@Override
public void delUser(int userId) {
checkSecurity();
userManager.delUser(userId);
}
@Override
public String findUserById(int userId) {
checkSecurity();
userManager.findUserById(userId);
return "zhangsan";
}
@Override
public void modifyUser(int userId,String username, String password) {
checkSecurity();
userManager.modifyUser();
}
@Override
public void checkSecurity() {
System.out.println("------UserManagerImpl.checkSecurity-----");
}
}
//測試類 ProxyTest.java
public class ProxyTest {
public static void main(String[] args) {
//在測試類中傳入具體實現類 UserManagerImpl,傳到代理的構造器中
UserManagerProxy userManagerProxy = new UserManagerProxy(new UserManagerImpl());
System.out.println(userManagerProxy.addUser("zhangsan","123456"));
}
}
以上,是一個簡單的靜態代理的例子,最需要注意的點如下:
(1) 代理類和具體的實現類繼承的是同一個接口
(2) 代理的實現對修改關閉,對擴展開放,也只是對具體實現類的擴展
(3) 客戶端通過代理去間接的調用到具體的實現類,在代理中會增加一部分控制邏輯
靜態代理缺陷: 在具體的實現類中有多少個接口,就需要加多少次邏輯,並且一次性只能代理一個固定的接口,不靈活,代碼不簡潔,所以出現了動態代理.
動態代理:
// 接口 UserManager.java
public interface UserManager {
public boolean addUser(String username, String password);
public void delUser(int userId);
public String findUserById(int userId);
public void modifyUser(int userId, String username, String password);
}
// 接口的實現類 UserManagerImpl.java
public class UserManagerImpl implements UserManager {
@Override
public boolean addUser(String username, String password) {
System.out.println("------UserManagerImpl.addUser-----");
return true;
}
@Override
public void delUser(int userId) {
System.out.println("------UserManagerImpl.delUser-----");
}
@Override
public String findUserById(int userId) {
System.out.println("------UserManagerImpl.findUserById-----");
return "zhangsan";
}
@Override
public void modifyUser(int userId,String username, String password) {
System.out.println("------UserManagerImpl.modifyUser-----");
}
}
//動態代理的核心類 SecurityHandler.java
//需要實現InvocationHandler 接口
public class SecurityHandler implements InvocationHandler {
private Object targetObject;
//通過 createProxyInstance 傳入具體的實現類
public Object createProxyInstance(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
//在 invoke 方法中加邏輯
checkSecurity();
//真正調用目標的方法
Object o1 = method.invoke(targetObject,objects);
return o1;
}
private void checkSecurity() {
System.out.println("------checkSecurity-----");
}
}
//動態代理測試類
public class Client {
SecurityHandler handler = new SecurityHandler();
//動態生成
//傳入真正的實現類 UserManagerImpl
UserManager userManager = (UserManager )handler.createProxyInstance(new UserManagerImpl());
System.out.println(userManager.addUser("zhangsan","123456"));
}
代理必須依賴真正的實現類存在,代理不能直接做具體的業務實現,只是一箇中間件的作用,在這個中間件中加了一些邏輯控制,如加入日誌,加入權限控制等,具體的業務實現還需要具體的實現類來完成。所以代理不能單獨存在,必須搭配實現類,並且和實現類實現同樣的接口。