前言
相信各位小夥伴在準備面試的時候,AOP都是無法繞過的一個點,經常能看到動态代理、JDK動态代理、CGLIB動态代理這樣的字眼。其實動态代理是代理模式的一種。代理模式有靜态代理、強制代理、動态代理。是以在認識AOP之前需要了解代理模式。
代理模式定義
代理模式(Proxy Pattern):為其他對象提供一種代理以控制這個對象的通路。
- Subject抽象主題角色,也叫做抽象主題類。可以是抽象類也可以是接口,是一個最普通的業務類型定義,無特殊要求。
- RealSubject具體主題角色,也叫做被委托角色,被代理角色,是業務邏輯的具體執行者。
- Proxy代理主題角色,也叫做委托類、代理類。他負責對真實角色的應用,把所有抽象主題類定義的方法限制委托給真實主題角色實作,并且在真實主題角色處理完畢前後做到預處理和善後工作。
代理模式的優點
- 職責清晰
- 高擴充性
- 智能化
UML
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLs1Wdf5mclRHdhB3X5h3byB3Lc5mclRHdhB3X5h3byB3Lcd2bsJ2Lc12bj5Sa1hmb1h3ZuFWdo5ycvN2Lc9CX6MHc0RHaiojIsJye.png)
我的了解
跳闆機不管是對于運維老哥還是對于我們來講,都是日常的工作中不可或缺的一個工具。為了保證生産伺服器的安全,我們是無法通過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讓你知道的。很顯然跳闆機對你來講就是透明的。
是以我們調整一下代碼,将其變成普通代理
public class JumpServer {
private Server server;
public JumpServer(Server server) {
this.server = server;
}
public void exec(String command){
server.exec(command);
}
}
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
強制代理
對于現實情況,我們可以通過不開放公網通路的權限來實作,強制使用代理操作伺服器。我們可以用代碼簡單的模拟下。
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動态代理來幫我們完成工作。