前言
相信各位小夥伴在準備面試的時候,AOP都是無法繞過的一個點,經常能看到動態代理、JDK動態代理、CGLIB動態代理這樣的字眼。其實動態代理是代理模式的一種。代理模式有靜態代理、強制代理、動態代理。所以在認識AOP之前需要了解代理模式。
代理模式定義
代理模式(Proxy Pattern):為其他對象提供一種代理以控制這個對象的訪問。
- Subject抽象主題角色,也叫做抽象主題類。可以是抽象類也可以是接口,是一個最普通的業務類型定義,無特殊要求。
- RealSubject具體主題角色,也叫做被委託角色,被代理角色,是業務邏輯的具體執行者。
- Proxy代理主題角色,也叫做委託類、代理類。他負責對真實角色的應用,把所有抽象主題類定義的方法限制委託給真實主題角色實現,並且在真實主題角色處理完畢前後做到預處理和善後工作。
代理模式的優點
- 職責清晰
- 高擴展性
- 智能化
UML
我的理解
跳板機不管是對於運維老哥還是對於我們來講,都是日常的工作中不可或缺的一個工具。為了保證生產服務器的安全,我們是無法通過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動態代理來幫我們完成工作。