Java代理講解

代理

代理模式是一種結構型設計模式,它允許我們通過添加一個代理對象來控制對另一個對象的訪問。代理對象和實際對象具有相同的接口,使得客戶端在不知情的情況下可以使用代理對象進行操作。代理對象在與客戶端進行交互時,可以控制對實際對象的訪問,以實現一些額外的功能,例如訪問計數、延遲加載、權限控制等。

代理分為靜態代理和動態代理兩種

靜態代理

靜態代理是指在編譯期間就已經確定代理類和被代理類的關系。代理類需要手動編寫,并且每個被代理類都需要一個對應的代理類

特點

  • 編譯期確定:在編譯代碼時,代理類的代碼就已經確定,之后不會再發生變化。
  • 代碼冗余:當有多個被代理類或者被代理類的方法很多時,會產生大量重復的代理代碼。
  • 靈活性差:如果被代理類的接口發生變化,代理類也需要相應地修改。

?下邊我們舉一個例子幫助大家進行了解

使用接口進行靜態代理

假設我們有一個叫cai的歌手,他只會進行singing和dance兩件事情,但是當它要開演唱會時,他要進行收錢才開始操作,但是收錢這個操作他只會專心執行sing和dance這個操作或者說他不會首先這個操作。這時就需要它的經紀人來幫助他進行收錢操作(代理)

定義cai歌手

public class Cai implements Singer {@Overridepublic void singing() {System.out.println("cai 唱歌");}@Overridepublic int dance() {System.out.println("cai 跳舞");return 0;}
}

定義cai代理

public class Caidaili implements  Singer{private Singer cai = new Cai();@Overridepublic void singing() {System.out.println("先收錢");cai.singing();}@Overridepublic int dance() {System.out.println("先收錢");cai.dance();return 0;}
}

他們都要實現Singer這個接口(代理模式的核心思想是通過代理對象來控制對真實對象的訪問,代理對象和真實對象需要對外提供一致的服務。接口定義了一組方法簽名,實現同一個接口能保證代理對象和被代理對象具有相同的方法,客戶端可以以相同的方式調用它們,從而實現對被代理對象的透明訪問。)

public interface Singer {void singing();int dance();
}

最后使用main方法進行調用

public static void main(String[] args) {Singer singer = new Caidaili();singer.singing();singer.dance();}

此時來了一位新的歌手為wu,他同樣會singing和dance,在假設其自己的方法和代理都實現時,我們只需要修改主代碼中的代理對象即可實現

使用繼承方式進行靜態代理

同樣的使用繼承方式我們也可以實現上述操作

public class Singer {public void dance(){System.out.println("cai 跳舞");}public int singing(){System.out.println("cai 唱歌");return 100;}
}

?使用被代理類繼承代理類

public class SingerSub extends Singer {@Overridepublic void dance() {System.out.println("收錢");super.dance();}@Overridepublic int singing() {System.out.println("收錢");return super.singing();}
}

?最后進行執行

public class Main {public static void main(String[] args) {Singer singer = new SingerSub();singer.singing();singer.dance();}
}

?

但是因為沒有接口的實現,我們每次進行都要使用代理類來承接這個被代理類

結合上邊的例子問題也隨之出現,因為我們在代理類中實例化了被代理類,每一個被代理類都要一個代理類在其內部進行實例化,每出現一個被代理類都要生成一個新的代理類進行代理,極為不方便。

此時,我們就需要一個擁有強大業務能力的“經紀人”(動態代理),來代理所有的被代理對象,不用我們進行頻繁的更換經紀人。

動態代理

從 靜態代理 章節中為我們可知,靜態代理存在著諸多的問題,最主要的問題是靜態代理類需要對被代理類做手動的方法映射。造成這個問題的原因是代理對象是通過硬編碼得到的,是在程序編譯前就已經存在的,所以順著這個思路,我們不難得到一個方向,如何代理對象不是通過硬編碼提前寫好的,而是在程序運行中動態生產的,且生成的代理對象可以對被代理類的方法做自動的映射,那么問題不就解決了嗎?是的,這也就是動態代理的大致解決方案。

JDK代理(基于接口實現)

我們同樣以上邊的cai歌手的例子為例

定義一個Singer的接口

public interface Singer {void dance();int singing();
}

?創建一個cai歌手進行實現它

public class Cai implements Singer {@Overridepublic void dance() {System.out.println("Cai 在跳舞");}@Overridepublic int singing() {System.out.println("Cai 在唱歌");return 0;}
}

最后我們使用JDK代理來進行代理cai類

public static void main(String[] args) {Cai cai  = new Cai();//第一個參數:類加載器//第二個參數:代理類需要實現的接口數組//第三個參數:InvocationHandler接口,其中包含了一個invoke方法,該方法會在每次調用代理對象的方法時被觸發Singer o = (Singer) Proxy.newProxyInstance(Cai.class.getClassLoader(), new Class[]{Singer.class}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if("singing".equals(method.getName())){System.out.println("先收錢");}else if("dance".equals(method.getName())){System.out.println("先收錢");}Object invoke = method.invoke(cai, args);//使用反射,將該方法作用到cai對象上return invoke;}});o.singing();}

?當我們想要修改被代理類,我們只需要修改

減少了,代理類的創建?

cglib代理(基于繼承進行實現)

創建一個cai對象

public class Cai {public void dance(){System.out.println("cai 跳舞");}public String singing(){System.out.println("cai 唱歌");return "謝謝";}}

創建代理cai的方法

public class CreateCglibProxy {public static Object getProxy(Object o){Enhancer enhancer = new Enhancer();//生成代理對象enhancer.setSuperclass(o.getClass());//將代理對象設置為被代理對象的子類enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object proxyObject, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {if("singing".equals(method.getName())){System.out.println("先收錢");}else if("dance".equals(method.getName())){System.out.println("先收錢");}Object invoke = methodProxy.invokeSuper(proxyObject, args);return invoke;}});return enhancer.create();}
}

最后進行執行

public class Main {public static void main(String[] args) {Cai cai = new Cai();Cai proxy = (Cai) CreateCglibProxy.getProxy(cai);proxy.dance();}
}

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

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

相關文章

利用deepseek快速生成甘特圖

一、什么是甘特圖 甘特圖(Gantt Chart)是一種直觀的項目管理工具,廣泛應用于多個領域,主要用于??時間規劃、任務分配和進度跟蹤??。 直觀性??:時間軸清晰展示任務重疊或延遲。 ??靈活性??:支持…

從零開始學習SLAM|技術路線

概念 視覺SLAM(Simultaneous Localization and Mapping)系統中,整個過程通常分為 前端 和 后端 兩個主要部分。前端處理的是從傳感器數據(如相機圖像、激光雷達等)中提取和處理信息,用于實時定位和建圖&am…

LeetCode 解題思路 44(Hot 100)

解題思路: dp 數組的含義: 以 nums[i] 為結尾的最長遞增子序列的長度。遞推公式: dp[i] Math.max(dp[i], dp[j] 1)。dp 數組初始化: dp[i] 1。遍歷順序: 從小到大去遍歷,從 i 1 開始,直到 …

精益數據分析(22/126):解鎖創業增長密碼與長漏斗分析

精益數據分析(22/126):解鎖創業增長密碼與長漏斗分析 在創業與數據分析的探索旅程中,我們都在不斷尋求新的知識和方法,以提升創業的成功率。我一直期望能和大家共同學習、共同進步,今天就讓我們繼續深入研…

大模型應用開發之LLM入門

一、大模型概述 1、大模型概念 LLM是指用有大量參數的大型預訓練語言模型,在解決各種自然語言處理任務方面表現出強大的能力,甚至可以展現出一些小規模語言模型所不具備的特殊能力 2、語言模型language model 語言建模旨在對詞序列的生成概率進行建模…

Vue 計算屬性 VS 偵聽器:從原理到性能的深度對比

在 Vue 開發中,computed(計算屬性)和watch(偵聽器)是響應式系統的兩大核心工具。 它們看似都能處理數據變化,實則設計理念和應用場景大相徑庭。 一、核心區別:數據驅動的兩種范式 1. 觸發機制…

特斯拉宣布啟動自動駕駛網約車測試,無人出租車服務進入最后準備階段

特斯拉公司于4月24日正式宣布,已在美國得克薩斯州奧斯汀和加利福尼亞州舊金山灣區啟動自動駕駛網約車服務的員工內部測試。這項測試將為今年夏季計劃推出的完全無人駕駛出租車服務進行最后的驗證和準備。 此次測試使用約200輛經過特殊改裝的Model 3車型,…

基于springboot的在線教育系統

一、系統架構 前端:vue | element-ui | html | jquery | css | ajax 后端:springboot | mybatis 環境:jdk1.8 | mysql | maven | nodejs | idea 二、代碼及數據 三、功能介紹 01. web端-首頁1 02. web端-首頁2 03. w…

文檔編輯:reStructuredText全面使用指南 — 第四部分 高級主題

文檔編輯:reStructuredText全面使用指南 — 第四部分 高級主題 reStructuredText(簡稱RST或ReST)是一種輕量級的標記語言,用于編寫結構化的文檔。它由Python社區開發,并廣泛應用于技術文檔、書籍、博客文章等。reStruc…

git Http改用戶下載

用原先別人賬號,無權下更新 http方式設置自己賬號 例如 git fetch --all 提示沒有權限從 http://192.168.1.2/gitlab/項目路徑.git下載 git remote set-url origin http://your-username192.168.1.2/gitlab/項目路徑.git your-username修改成自己的git賬號 需要輸入一個Tok…

Cancer Cell|scRNA-seq + scTCR + 空間多組學整合分析,揭示CD8? T細胞在免疫治療中的“雙路徑” | 臨床問題的組學解答

Cancer Cell|scRNA-seq scTCR 空間多組學整合分析,揭示CD8? T細胞在免疫治療中的“雙路徑” 👋 歡迎關注我的生信學習專欄~ 如果覺得文章有幫助,別忘了點贊、關注、評論,一起學習 近日,《Cancer Cell》…

Python編程的真諦:超越語法,理解編程本質

你是否也曾陷入這樣的誤區:學了無數的 Python 語法、刷了幾十套題,寫起代碼卻仍然卡頓、舉步維艱?這時候你才發現,真正阻礙進步的,從不是語法,而是你對“編程本質”的理解。 如果你只是死記硬背Python的語…

Go協程的調用與原理

Goroutine Go不需要像C或者Java那樣手動管理線程,Go語言的goroutine機制自動幫你管理線程。 使用goroutine、 Go語言中使用goroutine非常簡單,只需要在調用函數的時候在前面加上go關鍵字,就可以為一個函數創建一個goroutine。 一個gorout…

自然語言處理(9)—— 共現詞矩陣及Python實現

共現詞矩陣 1. 概述2. 構建步驟3. 代碼實現(Python)結語 共現詞矩陣(Co-occurrence Matrix)是自然語言處理(NLP)中用于捕捉詞語間語義關系的重要工具。共現矩陣通過統計詞語在特定上下文窗口內的共現頻率&a…

Spark SQL核心解析:大數據時代的結構化處理利器

在大數據處理領域,Spark以其強大的分布式計算能力脫穎而出,而Spark SQL作為Spark生態系統的重要組成部分,為結構化和半結構化數據處理提供了高效便捷的解決方案。它不僅整合了傳統SQL的強大查詢功能,還深度集成到Spark的計算框架中…

多態以及多態底層的實現原理

本章目標 1.多態的概念 2.多態的定義實現 3.虛函數 4.多態的原理 1.多態的概念 多態作為面對三大特性之一,它所指代的和它的名字一樣,多種形態.但是這個多種形態更多的指代是函數的多種形態. 多態分為靜態多態和動態多態. 靜態多態在前面已經學習過了,就是函數重載以及模板,…

linux下開發NFC讀寫器

linux下使用NFC讀卡器,基于QT5開發 創建工程,引入lib開始編寫代碼 創建工程,引入lib 創建一個QT工程,如果是控制臺程序,則去掉gui QT - gui引入lib庫 LIBS -L$$PWD/lib -lyw60x這里需要將libyw60x.so庫文件放在工程…

Linux基礎使用-筆記

1. 文件和目錄操作 查看當前目錄:pwd 命令用于顯示當前工作目錄的完整路徑。 pwd切換目錄:cd 命令用于切換工作目錄。 # 切換到指定目錄 cd /home/user/Documents # 切換到上一級目錄 cd .. # 切換到用戶主目錄 cd ~列出目錄內容:ls 命令用…

DAG(有向無環圖)計算模型面試內容整理-拓撲排序(Topological Sort)和節點依賴與并行度

拓撲排序(Topological Sort) 拓撲排序(Topological Sort): 拓撲排序是針對有向無環圖(DAG)的一種線性排序方法。這種排序方法的特點是,對于DAG中的每一條有向邊 (A → B),在拓撲排序中節點A總是排在節點B之前。

23種設計模式-結構型模式之享元模式(Java版本)

Java 享元模式(Flyweight Pattern)詳解 🦋 什么是享元模式? 享元模式是一種結構型模式,它通過共享相同的對象來減少內存消耗,適用于大量細粒度對象的場景。關鍵思想是緩存重復出現的對象,避免…