Android 動態代理詳解

Android 動態代理方法的原理與關鍵分析

動態代理是一種在運行時動態生成代理對象并攔截方法調用的技術。它廣泛應用于 Android 開發中,例如 AOP(面向切面編程)、插件化開發、網絡請求框架(如 Retrofit)等場景。

以下是動態代理的核心原理、關鍵實現步驟以及詳細分析:


1. 動態代理的核心原理

(1) 基于接口
  • 動態代理只能代理接口,而不能直接代理具體類。
  • 代理類實現了目標接口,并將方法調用委托給 InvocationHandler
(2) 方法攔截機制
  • 每次調用代理對象的方法時,都會觸發 InvocationHandler.invoke 方法。
  • invoke 方法中,可以執行額外邏輯(如日志記錄、權限檢查等),然后再調用目標對象的真實方法。
(3) 字節碼生成
  • 動態代理通過字節碼技術在運行時生成代理類。
  • JVM 內部使用 Proxy 類和 InvocationHandler 接口協作完成代理功能。

2. 動態代理的關鍵組件

(1) Proxy
  • 提供靜態方法 newProxyInstance,用于動態生成代理對象。
  • 代理對象實現了指定的接口,并將方法調用委托給 InvocationHandler
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
(2) InvocationHandler 接口
  • 定義了一個 invoke 方法,用于處理代理對象上的方法調用。
  • 每次調用代理對象的方法時,都會觸發 invoke 方法。
public interface InvocationHandler {Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

3. 動態代理的實現步驟

以下是動態代理的完整實現流程:

(1) 定義接口

定義一個接口,作為目標對象的行為規范。

interface ApiService {fun fetchData(): String
}
(2) 實現目標對象

創建一個類實現該接口。

class ApiServiceImpl : ApiService {override fun fetchData(): String {return "Real data from server"}
}
(3) 創建 InvocationHandler

實現 InvocationHandler 接口,定義方法調用的攔截邏輯。

class ApiProxyHandler(private val realApi: ApiService) : InvocationHandler {override fun invoke(proxy: Any?, method: Method, args: Array<out Any>?): Any? {println("Before method ${method.name} is called")// 調用真實對象的方法val result = method.invoke(realApi, *(args ?: arrayOf()))println("After method ${method.name} is called")return result}
}
(4) 動態生成代理對象

使用 Proxy.newProxyInstance 方法生成代理對象。

fun main() {// 創建目標對象val realApi = ApiServiceImpl()// 創建代理對象val proxy = Proxy.newProxyInstance(realApi.javaClass.classLoader,realApi.javaClass.interfaces,ApiProxyHandler(realApi)) as ApiService// 調用代理對象的方法val data = proxy.fetchData()println("Fetched data: $data")
}

輸出結果

Before method fetchData is called
After method fetchData is called
Fetched data: Real data from server

4. 動態代理的關鍵分析

(1) 方法調用流程

以下是動態代理中方法調用的完整流程:

  1. 調用代理對象的方法
    • 用戶調用代理對象的某個方法(如 proxy.fetchData())。
  2. 觸發 invoke 方法
    • 代理對象會捕獲方法調用,并將其轉發到 InvocationHandler.invoke
  3. 執行攔截邏輯
    • invoke 方法中,可以執行額外邏輯(如日志記錄、權限檢查等)。
  4. 調用目標對象的方法
    • 使用 Method.invoke 調用目標對象的真實方法。
  5. 返回結果
    • 將目標方法的返回值傳遞回調用方。
(2) 字節碼生成機制
  • 動態代理通過字節碼技術生成代理類。
  • 生成的代理類結構類似于以下偽代碼:

public final class $Proxy0 extends Proxy implements ApiService {private InvocationHandler handler;public $Proxy0(InvocationHandler handler) {this.handler = handler;}@Overridepublic String fetchData() {try {return (String) handler.invoke(this, ApiService.class.getMethod("fetchData"), null);} catch (Throwable t) {throw new RuntimeException(t);}}
}
(3) 性能開銷
  • 動態代理基于反射,性能略低于直接調用。
  • 如果對性能要求較高,可以通過緩存 Method 對象或使用其他優化手段。

5. 動態代理的實際應用場景

(1) 網絡請求框架(Retrofit)
  • Retrofit 使用動態代理將接口方法映射為 HTTP 請求。
  • 示例:
    interface ApiService {@GET("users/{id}")fun getUser(@Path("id") id: Int): Call<User>
    }val retrofit = Retrofit.Builder().baseUrl("https://api.example.com/").build()val apiService = retrofit.create(ApiService::class.java)
    
(2) 數據庫操作(Room)
  • Room 使用動態代理將 DAO 接口方法映射為 SQL 查詢。
  • 示例:
    @Dao
    interface UserDao {@Query("SELECT * FROM users WHERE id = :id")fun getUserById(id: Int): User
    }
    
(3) 插件化開發
  • 動態代理可用于加載和管理插件模塊,動態替換或增強功能。
(4) 權限管理
  • 動態代理可用于統一檢查權限,避免在每個方法中手動檢查。
class PermissionProxyHandler(private val realApi: ApiService) : InvocationHandler {override fun invoke(proxy: Any?, method: Method, args: Array<out Any>?): Any? {if (!hasPermission()) {throw SecurityException("Permission denied")}return method.invoke(realApi, *(args ?: arrayOf()))}private fun hasPermission(): Boolean {// 檢查權限邏輯return true}
}

6. 關鍵點總結

  1. 核心原理

    • 動態代理基于接口,通過 ProxyInvocationHandler 實現方法攔截。
    • 每次調用代理對象的方法時,都會觸發 InvocationHandler.invoke
  2. 方法調用流程

    • 調用代理對象的方法 → 觸發 invoke → 執行攔截邏輯 → 調用目標方法 → 返回結果。
  3. 字節碼生成

    • 動態代理通過字節碼技術生成代理類,代理類實現了目標接口。
  4. 實際應用

    • 網絡請求框架(如 Retrofit)。
    • 數據庫操作(如 Room)。
    • 插件化開發。
    • 權限管理。
  5. 限制與優化

    • 只能代理接口,無法代理具體類。
    • 性能開銷較大,可通過緩存 Method 對象或使用其他優化手段。

通過理解動態代理的原理和實現細節,可以在 Android 開發中靈活應用這一技術,提升代碼的可維護性和擴展性。

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

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

相關文章

碰一碰發視頻saas系統技術源頭一站式開發文檔

碰一碰發視頻系統技術源頭一站式開發文檔 一、引言 在數字化信息傳播高速發展的當下&#xff0c;如何讓視頻分享更便捷、高效&#xff0c;成為商家和開發者們關注的焦點。“碰一碰發視頻”系統以其獨特的交互方式和強大的功能優勢&#xff0c;為視頻分享領域帶來了革命性變革。…

VSCode + CMake

參考文獻&#xff1a; 如何用 GCC, CMake 和 Make 編譯C/C代碼Windows 上的 Linux 子系統&#xff1a;WSLWSL&#xff1a;桌面 UI 遠程連接 RDP 配置 VScode 文章目錄 CMake 配置VSCode 配置launch.jsontask.jsonc_cpp_properties.json CMake 配置 編寫如下的 CmakeLists.t…

yolov5學習及手勢識別實戰

目錄 一、YOLOv5核心原理 1. 單階段檢測范式 2. 關鍵技術特性 二、YOLOv5網絡架構組成 1. Backbone&#xff1a;CSPDarknet53 2. Neck&#xff1a;PANet&#xff08;Path Aggregation Network&#xff09; 3. Head&#xff1a;檢測頭 三、YOLOv5網絡架構細節 1. 整體架…

【視頻】H.264的碼率和圖像質量

1、簡述 分辨率、幀率、I幀設置不變的情況下,碼率過低時,IP攝像機如果沒有足夠的帶寬來傳輸高質量的圖像,便會抹掉一些細節,導致出現馬賽克,尤其是動態性強的畫面(比如:運動的云臺、非固定的攝像頭)。 2、計算碼率 1)碼率的基礎理論公式為: 碼率 (bps) = 分辨率像…

VMware-workstation-17.6.3安裝教程

1.下載VMware-workstation-17.6.3軟件包 2.安裝并輸入許可碼 3.開始使用

[Linux][經驗總結]Ubuntu6.11.0 docker更換鏡像源(實操可用的正確方法)

一、前言 關于Ubuntu更換docker鏡像源&#xff0c;網上有很多的教程&#xff0c;但在實操中發現&#xff0c;更換的源無法生效——原因是我的docker是在系統安裝時&#xff0c;選擇附加安裝的package的方式安裝的。 現將處理過程記錄如下。 二、獲取鏡像源 在網上隨便找個幾…

Element Plus開發實戰指南:快速上手Vue 3企業級組件庫

Element Plus全棧開發指南&#xff1a;從入門到企業級實戰 一、環境搭建與工程配置1.1 項目初始化&#xff08;Windows/Mac通用&#xff09;1.2 配置文件關鍵代碼 二、主題定制與樣式管理2.1 SCSS變量覆蓋方案2.2 暗黑模式切換 三、核心組件深度實踐3.1 智能表格開發&#xff0…

Elasticsearch基礎教程:從入門到上手

&#x1f3af; 一、Elasticsearch簡介 Elasticsearch&#xff08;簡稱ES&#xff09;是一個分布式、RESTful風格的搜索引擎&#xff0c;支持全文檢索、結構化查詢、分析和近實時搜索。常用于日志分析、商品搜索、數據分析等場景。 1. 什么是 Elasticsearch&#xff1f; Elas…

VIVO手機如何實現證件照換底色?證件照換底色技巧分享

在日常生活中&#xff0c;我們常常需要使用不同底色的證件照&#xff0c;無論是辦理證件、提交資料還是其他用途&#xff0c;一張符合要求的證件照都顯得尤為重要。 而VIVO手機憑借其強大的拍照功能和便捷的圖片編輯工具&#xff0c;為我們提供了一種簡單高效的證件照換底色解…

A SURVEY ON POST-TRAINING OF LARGE LANGUAGE MODELS——大型語言模型的訓練后優化綜述——第一部分

arXiv 2025 摘要 大型語言模型&#xff08;LLMs&#xff09;的出現從根本上改變了自然語言處理&#xff0c;使其在從對話系統到科學研究的各個領域中變得不可或缺。然而&#xff0c;它們的預訓練架構在特定情境下經常顯示出局限性&#xff0c;包括有限的推理能力、倫理不確定…

深入理解Python閉包與遞歸:原理、應用與實踐

目錄 閉包 什么是閉包&#xff1a; 閉包的基本結構&#xff1a; 實現閉包的條件&#xff1a; 1.嵌套函數 2.內函數引用外部函數的變量 3.外部函數返回內部函數 4.外部函數已經執行完畢 遞歸函數 什么是遞歸函數&#xff1a; 遞歸函數條件 1.必須有個明確的結束條…

【自學筆記】智能合約基礎知識點總覽-持續更新

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 智能合約基礎知識點總覽目錄1. 智能合約簡介2. 以太坊與Solidity示例代碼&#xff1a;Hello World智能合約 3. Solidity基礎語法示例代碼&#xff1a;簡單的計數器合…

ABAP PDF預覽

畫個屏幕 PDF JPG TXT都可以參考預覽&#xff0c;把二進制流傳遞給標準函數就行 *&---------------------------------------------------------------------* *& Report YDEMO2 *&---------------------------------------------------------------------* *&am…

【視頻】文本挖掘專題:Python、R用LSTM情感語義分析實例合集|上市銀行年報、微博評論、紅樓夢、汽車口碑數據采集詞云可視化

原文鏈接&#xff1a;https://tecdat.cn/?p41149 分析師&#xff1a;Zhenzhen Liu&#xff0c;Shuai Fung 作為數據科學家&#xff0c;我們始終關注如何從非結構化數據中提取高價值信息。本專題合集聚焦企業年報的文本分析技術&#xff0c;通過Python與R語言實戰案例&#xff…

高效團隊開發的工具與方法 引言

引言 在現代軟件開發領域&#xff0c;團隊協作的效率和質量直接決定了項目的成敗。隨著項目規模的擴大和技術復雜度的增加&#xff0c;如何實現高效團隊開發成為每個開發團隊必須面對的挑戰。高效團隊開發不僅僅是個人技術能力的簡單疊加&#xff0c;更需要借助合適的工具和方…

python中mysql操作整理

安裝 Windows &#xff1a; pip install pymysql -i https://pypi.douban.com/simple mac &#xff1a;python3 -m pip install pymysql -i https://pypi.douban.com/simple mysql示例 import pymysql connect pymysql.Connect(host82.156.74.26,port3306,userroot,passwor…

Python----計算機視覺處理(Opencv:圖像顏色替換)

一、開運算 開運算就是對圖像先進行腐蝕操作&#xff0c; 然后進行膨脹操作。開運算可以去除二值化圖中的小的噪點&#xff0c;并分離相連的物體。 其主要目的就是消除那些小白點 在開運算組件中&#xff0c;有一個叫做kernel的參數&#xff0c;指的是核的大小&#xff0c;通常…

基于SpringBoot的“ERP-物資管理”的設計與實現(源碼+數據庫+文檔+PPT)

基于SpringBoot的“ERP-物資管理”的設計與實現&#xff08;源碼數據庫文檔PPT) 開發語言&#xff1a;Java 數據庫&#xff1a;MySQL 技術&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系統展示 系統總體結構圖 E-R實體關系圖 管理員登錄界面 管…

鏈表操作:分區與回文判斷

目錄 鏈表分區&#xff08;Partition&#xff09; 功能概述 代碼實現 要點與難點 注意事項 鏈表回文判斷&#xff08;PalindromeList&#xff09; 功能概述 代碼實現 要點與難點 注意事項 總結 在鏈表相關的算法問題中&#xff0c;理解鏈表的基本結構和操作至關重要…

如何在 Node.js 中使用 .env 文件管理環境變量 ?

Node.js 應用程序通常依賴于環境變量來管理敏感信息或配置設置。.env 文件已經成為一種流行的本地管理這些變量的方法&#xff0c;而無需在代碼存儲庫中公開它們。本文將探討 .env 文件為什么重要&#xff0c;以及如何在 Node.js 應用程序中有效的使用它。 為什么使用 .env 文…