代理---靜態代理--動態代理

首先,明確一點:代理不會改變之前寫的所有代碼,代理需要繼承相同的接口。

那麼問題來了,爲什麼要用到代理?

假設有一個接口 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"));

}

代理必須依賴真正的實現類存在,代理不能直接做具體的業務實現,只是一箇中間件的作用,在這個中間件中加了一些邏輯控制,如加入日誌,加入權限控制等,具體的業務實現還需要具體的實現類來完成。所以代理不能單獨存在,必須搭配實現類,並且和實現類實現同樣的接口。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章