開發與維運

面試問到AOP就該這樣回答

前言

  相信各位小夥伴在準備面試的時候,AOP都是無法繞過的一個點,經常能看到動態代理、JDK動態代理、CGLIB動態代理這樣的字眼。其實動態代理是代理模式的一種。代理模式有靜態代理、強制代理、動態代理。所以在認識AOP之前需要了解代理模式。

代理模式定義

  代理模式(Proxy Pattern):為其他對象提供一種代理以控制這個對象的訪問。

  • Subject抽象主題角色,也叫做抽象主題類。可以是抽象類也可以是接口,是一個最普通的業務類型定義,無特殊要求。
  • RealSubject具體主題角色,也叫做被委託角色,被代理角色,是業務邏輯的具體執行者。
  • Proxy代理主題角色,也叫做委託類、代理類。他負責對真實角色的應用,把所有抽象主題類定義的方法限制委託給真實主題角色實現,並且在真實主題角色處理完畢前後做到預處理和善後工作。

代理模式的優點

  • 職責清晰
  • 高擴展性
  • 智能化

UML

image

我的理解

  跳板機不管是對於運維老哥還是對於我們來講,都是日常的工作中不可或缺的一個工具。為了保證生產服務器的安全,我們是無法通過xshell等工具直接進行連接的。如果需要操作生產的服務器,則需要通過跳板機。並且跳板機還能記錄我們的操作,用來做安全審計。防止出現,某位老哥一氣之下反手就是個sudo rm -rf /*直接涼涼。


  我們回過頭看看代理模式的定義:為其他對象提供一種代理以控制這個對象的訪問。實際上跳板機就是生產服務器的一個代理Proxy,為了實現控制生產服務器的訪問權限。你需要通過跳板機來操作生產服務器。

  • 為其他對象提供一種代理以控制這個對象的訪問
  • 給你提供一個跳板機來訪問生產服務器,目的是來控制生產服務器的訪問

  Proxy的職責:Proxy是對真實角色的應用,把所有抽象主題類定義的方法限制委託給真實主題角色實現。並且在真實主題角色處理完畢前後做到預處理善後工作。你通過操作跳板機。跳板機將你輸入的命令在生產服務器上進行執行。並且能記錄下執行的命令和執行的結果。

代碼演示

Server

public interface Server {

    /**
     * 執行
     * @param command 命令
     */
    void exec(String command);

}

ProdServer

public class ProdServer implements Server {

    @Override
    public void exec(String command){
        System.out.println(command + ":執行成功");
    }

}

JumpServer

public class JumpServer {

    private Server server;

    public JumpServer(Server server) {
        this.server = server;
    }

    public void exec(String command){
        System.out.println("xxx在:" + LocalDateTime.now() + " 執行了:" + command);
        server.exec(command);
        System.out.println("xxx在:" + LocalDateTime.now() + " 執行完了:"+ command + " 結果是XXX");
    }

}

Client

public class Client {

    public static void main(String[] args) {
        JumpServer jumpServer = new JumpServer();
        jumpServer.exec("pwd");
    }
}

運行結果

xxx在:2020-04-04T16:43:19.277 執行了:pwd
pwd:執行成功
xxx在:2020-04-04T16:43:19.278 執行完了:pwd 結果是XXX

  通過上面的代碼,簡單的實現了代理模式。在網絡上代理服務器設置分為透明代理普通代理

  • 透明代理就是用戶不用設置代理服務器地址,就可以直接訪問.也就是說代理服務器對用戶來說是透明的,不用知道它存在的。
  • 普通代理則是需要用戶自己設置代理服務器的IP地址,用戶必須知道代理的存在。

  當運維老哥給了一臺服務器的賬號和密碼,你成功登錄,並完成了相應的操作。你以為給你的是生產的服務器。實際就可能是個跳板機。為了安全起見,是不可能將實際服務器的IP讓你知道的。很顯然跳板機對你來講就是透明的。

所以我們調整一下代碼,將其變成普通代理

JumpServer

public class JumpServer {

    private Server server;

    public JumpServer(Server server) {
        this.server = server;
    }

    public void exec(String command){
        server.exec(command);
    }

}

Client

public class Client {

    public static void main(String[] args) {
        ProdServer prodServer = new ProdServer();
        JumpServer jumpServer = new JumpServer(prodServer);
        jumpServer.exec("pwd");
    }
    
}

執行結果

xxx在:2020-04-04T16:52:23.282 執行了:pwd
pwd:執行成功
xxx在:2020-04-04T16:52:23.283 執行完了:pwd 結果是XXX

強制代理

  對於現實情況,我們可以通過不開放公網訪問的權限來實現,強制使用代理操作服務器。我們可以用代碼簡單的模擬下。

JumpServer

public class ProdServer implements Server {

    private JumpServer jumpServer;

    @Override
    public void exec(String command){
        hasProxy();
        System.out.println(command + ":執行成功");
    }

    private void hasProxy(){
        if(jumpServer == null){
            throw new RuntimeException("請使用跳板機!");
        }
    }

    public JumpServer setJumpServer() {
        this.jumpServer = new JumpServer(this);
        return this.jumpServer;
    }
}

Client未設置跳板機

public class Client {

    public static void main(String[] args) {
        ProdServer prodServer = new ProdServer();
        prodServer.exec("pwd");
    }

}

這個時候需要訪問生產服務器,就需要先設置跳板機了,才能進行操作。

動態代理

  對靜態代理來說,我們需要手動生成代理類。但是如果需要代理的類太多了,那這個肯定是不可取的。所以我們可以使用JDK動態代理來幫我們完成工作。

Leave a Reply

Your email address will not be published. Required fields are marked *