Java 代理(一) 靜態代理

學習代理的設計模式的時候,經常碰到的一個經典場景就是想統計某個方法的執行時間。

1 靜態代理模式的產生

需求1. 統計方法執行時間

統計方法執行時間,在很多API/性能監控中都有這個需求。

下面以簡單的計算器為例子,計算加法耗時。代碼如下:


public Long add(Integer a, Integer b) {long result = 0;for(int i=0; i<100000000; i++) {result += i + a + b;}return result;
}

方法很簡單,就是計算兩數之和。這里為了方便統計耗時,所以循環了很多次。

統計耗時,那么實現起來也很簡單:

public Long add(Integer a, Integer b) {long start = System.currentTimeMillis();long result = 0;for(int i=0; i<100000000; i++) {result += i + a + b;}long end = System.currentTimeMillis();System.out.println("cost time: " + (end - start) + "ms");return result;}

統計代碼和業務代碼,雜糅在一起,是否是感覺有點混亂,有沒有一種方法:在不影響原有業務邏輯情況下實現統計耗時的功能?

需求2.不影響原有業務邏輯,實現方法的耗時統計

很快我們想到一種方法,那就是定義一個父類,專門做耗時統計,業務代碼通過抽象方法定義,子類擴展具體的業務方法即可。

代碼如下:

public abstract class AbstractTime {public Long tickTock(Integer a, Integer b) {long start = System.currentTimeMillis();long result = calculate(a,b);long end = System.currentTimeMillis();System.out.println("cost time: " + (end - start) + "ms");return result;}protected abstract Long add(Integer a, Integer b);
}

計算加法的耗時統計如下:
?

public class AddTime extends AbstractTime {@Overridepublic Long add(Integer a, Integer b) {long result = 0;for(int i=0; i<100000000; i++) {result += i + a + b;}return result;}public static void main(String[] args){AddTime addTime = new AddTime();addTime.tickTock(1, 2);}
}

很好,實現無侵入式統計方法耗時,完成既定目標。

那么問題又來了,假如我們這個方法還需要繼承另外一個類,這個時候怎么辦呢?

需求3:使用接口方式,實現無侵入式統計方法耗時

我們先把需要實現的業務邏輯,通過接口的方式封裝起來,定義一個接口。

public interface Calculator {Long add(Integer a, Integer b);
}

實現業務接口的方法類:

public class AddCalculator implements Calculator {@Overridepublic Long calculate(Integer a, Integer b) {long result = 0;for(int i=0; i<100000000; i++) {result += i + a + b;}return result;}
}

使用接口,無侵入式實現方法耗時統計的方案就是,設計模式里的經典方案:代理模式。

這里使用代理模式,實現的代理類如下:

public class AddCalculatorProxy implements Calculator {private Calculator calculator;public AddCalculatorProxy(Calculator calculator) {this.calculator = calculator;}@Overridepublic Long calculate(Integer a, Integer b) {long start = System.currentTimeMillis();// 具體的業務邏輯類Long result = calculator.add(a, b);long end = System.currentTimeMillis();System.out.println("cost time: " + (end - start) + "ms");return result;}public static void main(String[] args) {Calculator calculator = new AddCalculator();Calculator proxy = new AddCalculatorProxy(calculator);proxy.add(1, 2);}
}

這就是靜態代理模式的推演過程。

2. 靜態代理模式是什么

靜態代理模式是一種設計模式,用于在不修改目標對象的前提下,通過代理對象來控制對目標對象的訪問。以下是關于靜態代理模式的詳細說明:


2.1. 定義

靜態代理模式中,代理類和目標類實現相同的接口,代理類持有目標類的實例,并通過代理類間接調用目標類的方法。代理類可以在方法執行前后添加額外的邏輯。


2.2. 特點

接口:目標類和代理類都實現了同一個接口。
代理類:代理類持有一個目標類的引用,并在其方法中調用目標類的方法。
擴展性:可以在不修改目標類的情況下,通過代理類添加額外的功能(如日志記錄、性能監控等)。


2.3. 代碼分析

根據上面的例子,以下是對靜態代理模式的實現分析:

接口定義

public interface Calculator {Long add(Integer a, Integer b);
}

定義了一個 Calculator 接口,包含一個 add 方法。

目標類:

public class AddCalculator implements Calculator {@Overridepublic Long calculate(Integer a, Integer b) {long result = 0;for(int i=0; i<100000000; i++) {result += i + a + b;}return result;}
}

AddCalculator 是目標類,實現了 Calculator 接口。
提供了具體的業務邏輯(例如計算兩個數的和并進行循環累加)。

代理類

public class AddCalculatorProxy implements Calculator {private Calculator calculator;public AddCalculatorProxy(Calculator calculator) {this.calculator = calculator;}@Overridepublic Long calculate(Integer a, Integer b) {long start = System.currentTimeMillis();// 調用目標類的業務邏輯Long result = calculator.add(a, b);long end = System.currentTimeMillis();System.out.println("cost time: " + (end - start) + "ms");return result;}
}

AddCalculatorProxy 是代理類,也實現了 Calculator 接口。
持有一個 Calculator 類型的目標類實例。
在 calculate 方法中,代理類在調用目標類的 add 方法前后添加了時間統計的邏輯。

測試代碼

public static void main(String[] args) {Calculator calculator = new AddCalculator();Calculator proxy = new AddCalculatorProxy(calculator);proxy.add(1, 2);
}

創建目標類實例 AddCalculator。
使用代理類 AddCalculatorProxy 包裝目標類實例。
調用代理類的 add 方法時,會自動執行代理類中的額外邏輯(如性能統計)。


2.4. 優點

職責分離:將核心業務邏輯與附加功能分離,符合單一職責原則。
增強功能:可以在不修改目標類的情況下,通過代理類添加新的功能。


2.5. 缺點

代碼膨脹:每新增一個目標類,就需要創建一個對應的代理類,可能導致代碼量增加。
靈活性不足:代理類和目標類必須實現相同的接口,缺乏動態性。


2.6. 總結

靜態代理模式適用于需要在目標類的基礎上擴展功能的場景。它通過代理類封裝目標類的行為,同時保持接口的一致性。例子代碼很好地展示了靜態代理模式的應用,通過代理類實現了性能監控的功能。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/899370.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/899370.shtml
英文地址,請注明出處:http://en.pswp.cn/news/899370.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

每日總結3.28

藍橋刷題 3227 找到最多的數 方法一&#xff1a;摩爾投票法 #include <bits/stdc.h> using namespace std; #define int long long signed main() { int n,m; cin>>n>>m; int a[m*n]; for(int i0;i<n*m;i) { cin>>a[i]; } int cand…

Flutter快速搭建聊天

之前項目中使用的環信聊天&#xff0c;我們的App使用的Flutter開發的 。 所以&#xff0c;就使用的 em_chat_uikit &#xff0c;這個是環信開發的Flutter版本的聊天。 一開始&#xff0c;我們也用的環信的聊天&#xff0c;是收費的&#xff0c;但是&#xff0c;后面就發現&…

Sa-Token

簡介 Sa-Token 是一個輕量級 Java 權限認證框架&#xff0c;主要解決&#xff1a;登錄認證、權限認證、單點登錄、OAuth2.0、分布式Session會話、微服務網關鑒權 等一系列權限相關問題。 官方文檔 常見功能 登錄認證 本框架 用戶提交 name password 參數&#xff0c;調用登…

基于javaweb的SSM航班機票預訂平臺系統設計與實現(源碼+文檔+部署講解)

技術范圍&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬蟲、數據可視化、小程序、安卓app、大數據、物聯網、機器學習等設計與開發。 主要內容&#xff1a;免費功能設計、開題報告、任務書、中期檢查PPT、系統功能實現、代碼編寫、論文編寫和輔導、論…

格雷碼、漢明碼,CRC校驗的區別

格雷碼、漢明碼和CRC校驗都是用于數據傳輸和存儲中的編碼技術。 它們在原理、功能和應用場景上存在顯著區別。 1.格雷碼&#xff08;Gray Code&#xff09; ? 定義&#xff1a;格雷碼是一種特殊的二進制編碼&#xff0c;任意兩個相鄰的碼字之間僅有一位不同。 ? 功能&#x…

【報錯】 /root/anaconda3/conda.exe: cannot execute binary file: Exec format error

背景: 安裝Anaconda3 bash Anaconda3-****-Linux-x86_64.sh 報錯: /root/anaconda3/conda.exe: cannot execute binary file: Exec format error 原因分析: 安裝包(如

JAVA實現動態IP黑名單過濾

一些惡意用戶(可能是黑客、爬蟲、DDoS 攻擊者)可能頻繁請求服務器資源&#xff0c;導致資源占用過高。因此需要一定的手段實時阻止可疑或惡意的用戶&#xff0c;減少攻擊風險。 通過 IP 封禁&#xff0c;可以有效拉黑攻擊者&#xff0c;防止資源被濫用&#xff0c;保障合法用戶…

開源的CMS建站系統可以隨便用嗎?有什么需要注意的?

開源CMS建站系統雖然具有許多優點&#xff0c;但并非完全“隨便用”。無論選哪個CMS系統&#xff0c;大家在使用的時候&#xff0c;可以盡可能地多注意以下幾點&#xff1a; 1、版權問題 了解開源許可證&#xff1a;不同的開源CMS系統采用不同的開源許可證&#xff0c;如GPL、…

故障識別 | 基于改進螂優化算法(MSADBO)優化變分模態提取(VME)結合稀疏最大諧波噪聲比解卷積(SMHD)進行故障診斷識別,matlab代碼

基于改進螂優化算法&#xff08;MSADBO&#xff09;優化變分模態提取&#xff08;VME&#xff09;結合稀疏最大諧波噪聲比解卷積&#xff08;SMHD&#xff09;進行故障診斷識別 一、引言 1.1 機械故障診斷的背景和意義 在工業生產的宏大畫卷中&#xff0c;機械設備的穩定運行…

探究 CSS 如何在HTML中工作

2025/3/28 向全棧工程師邁進&#xff01; 一、CSS的作用 簡單一句話——美化網頁 <p>Lets use:<span>Cascading</span><span>Style</span><span>Sheets</span> </p> 對于如上代碼來說&#xff0c;其顯示效果如下&#xff1…

硬件老化測試方案的設計誤區

硬件老化測試方案設計中的常見誤區主要包括測試周期不足、測試條件過于單一、樣品選擇不當等方面。其中&#xff0c;測試周期不足尤為突出&#xff0c;容易導致潛在缺陷未被完全暴露。老化測試本質上是通過加速產品老化來模擬長期使用狀況&#xff0c;因此測試周期不足會嚴重削…

無錫零碳園區“三年突圍”安科瑞源網荷儲充系統如何破解“綠電難、儲能貴、調度亂”困局?

零碳園區建設如火如荼&#xff0c;為何企業“不敢投、不會用”&#xff1f; 無錫市政府3月27日發布《零碳園區建設三年行動方案》&#xff0c;目標到2027年建成10家以上零碳園區、20家零碳工廠、10個源網荷儲一體化項目。但企業仍存疑慮&#xff1a; 綠電消納難&#xff1a;光…

docker torcherve打包mar包并部署模型

使用Docker打包深度網絡模型mar包到服務端 參考鏈接&#xff1a;Docker torchserve 部署模型流程——以WSL部署YOLO-FaceV2為例_class myhandler(basehandler): def initialize(self,-CSDN博客 1、docker拉取環境鏡像命令 docker images出現此提示為沒有權限取執行命令&…

Redis 分布式鎖實現深度解析

Redis 分布式鎖是分布式系統中協調多進程/服務對共享資源訪問的核心機制。以下從基礎概念到高級實現進行全面剖析。 一、基礎實現原理 1. 最簡實現&#xff08;SETNX 命令&#xff09; # 加鎖 SET resource_name my_random_value NX PX 30000# 解鎖&#xff08;Lua腳本保證原…

kubernetes》》k8s》》 kubeadm、kubectl、kubelet

kubeadm 、kubectl 、kubelet kubeadm、kubectl和kubelet是Kubernetes中不可或缺的三個組件。kubeadm負責集群的快速構建和初始化&#xff0c;為后續的容器部署和管理提供基礎&#xff1b;kubectl作為命令行工具&#xff0c;提供了與Kubernetes集群交互的便捷方式&#xff1b;而…

linux 硬盤擴展

場景&#xff1a; [rootlocalhost ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8:0 0 40G 0 disk ├─sda1 8:1 0 1M 0 part ├─sda2 8:2 0 1G 0 part /boot └─sda3 …

Docker Desktop 界面功能介紹

Docker Desktop 界面功能介紹 左側導航欄 Containers(容器): 用于管理容器,包括查看運行中或已停止的容器,檢查容器狀態、日志,執行容器內命令,啟動、停止、刪除容器等操作。Images(鏡像): 管理本地 Docker 鏡像,可查看鏡像列表、從 Docker Hub 拉取新鏡像、刪除鏡…

C++細節知識for面試

1. linux上C程序可用的棧和堆大小分別是多少&#xff0c;為什么棧大小小于堆&#xff1f; 1. 棧&#xff08;Stack&#xff09;大小 棧默認為8MB&#xff0c;可修改。 為什么是這個大小&#xff1a; ?安全性&#xff1a;限制棧大小可防止無限遞歸或過深的函數調用導致內存…

數據設計(范式、步驟)

文章目錄 數據設計1.數據庫設計的三大范式2、數據庫設計的具體步驟 數據設計 1.數據庫設計的三大范式 關系型數據庫的三大范式&#xff0c;指導如何設計一個關系型數據庫。 1NF&#xff1a; 關系表的每個字段&#xff0c;都應該是不可再分的&#xff0c;——保證原子性。 字…

PhotoShop學習03

1.更改圖像大小 通常情況下&#xff0c;如果我們想在某些上傳圖片&#xff0c;會發現我們的圖片可能會過大或者過小&#xff0c;為此&#xff0c;我們需要調整圖像的大小&#xff0c;使之符合網站的規則。 首先打開photoshop&#xff0c;打開一張圖片。首先我們需要了解這張圖…