jdk動態代理如何實現

口語化答案

好的,面試官。jdk 的動態代理主要是依賴Proxy類InvocationHandler 接口。jdk 動態代理要求類必須有接口。在進行實現的時候,首先要定義接口,比如MyService,這個接口就是我們的正常功能的實現。但是希望在不更改MyService 的情況下增加額外功能,那么我們需要定義一個實現InvocationHandler 接口的實現類,同時在方法實現上面增加額外的邏輯。最后通過 Proxy 的 newProxyInstance 將二者結合到一起。就實現了動態代理。

題目解析

大家不要覺得動態代理很難理解,按照這個步驟其實你發現很簡單。記憶的過程和 cglib 對比著看,就很輕松,面試也是屬于常考一點的題目。

面試得分點

InvocationHandler 增強,Proxy 創建代理

題目詳細答案

JDK 動態代理主要依賴于java.lang.reflect.Proxy類和java.lang.reflect.InvocationHandler接口來實現。

實現步驟

定義接口:定義需要代理的接口。

實現接口:創建接口的實現類。

創建調用處理器:實現InvocationHandler接口,并在invoke方法中定義代理邏輯。

創建代理對象:通過Proxy.newProxyInstance方法創建代理對象。

代碼 Demo

假設我們有一個簡單的服務接口MyService和它的實現類MyServiceImpl,我們將通過 JDK 動態代理為MyService創建一個代理對象,并在方法調用前后添加日志。

1. 定義接口
public interface MyService {void performTask();
}
2. 實現接口
public class MyServiceImpl implements MyService {@Overridepublic void performTask() {System.out.println("Performing task");}
}
3. 創建調用處理器
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class LoggingInvocationHandler implements InvocationHandler {private final Object target;public LoggingInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Logging before method execution: " + method.getName());Object result = method.invoke(target, args);System.out.println("Logging after method execution: " + method.getName());return result;}
}
4. 創建代理對象并使用
import java.lang.reflect.Proxy;public class MainApp {public static void main(String[] args) {// 創建目標對象MyService myService = new MyServiceImpl();// 創建調用處理器LoggingInvocationHandler handler = new LoggingInvocationHandler(myService);// 創建代理對象MyService proxyInstance = (MyService) Proxy.newProxyInstance(myService.getClass().getClassLoader(),myService.getClass().getInterfaces(),handler);// 調用代理對象的方法proxyInstance.performTask();}
}

詳細解釋

1、 接口定義和實現

MyService是一個簡單的接口,定義了一個方法performTask。

MyServiceImpl是MyService的實現類,實現了performTask方法。

2、 調用處理器

LoggingInvocationHandler實現了InvocationHandler接口。它的invoke方法在代理對象的方法調用時被調用。invoke方法接收三個參數:proxy:代理對象。method:被調用的方法。args:方法參數。在invoke方法中,我們在方法調用前后添加了日志打印。

3、 創建代理對象

使用Proxy.newProxyInstance方法創建代理對象。

newProxyInstance方法接收三個參數:類加載器:通常使用目標對象的類加載器。接口數組:目標對象實現的所有接口。調用處理器:實現了InvocationHandler接口的實例。

4、 使用代理對象

通過代理對象調用方法時,實際調用的是LoggingInvocationHandler的invoke方法。

在invoke方法中,首先打印日志,然后通過反射調用目標對象的方法,最后再打印日志。

JDK動態代理通俗詳解

面試官您好,關于JDK動態代理,我用一個生活中的例子來幫助理解:

快遞代收點類比

想象你網購了一件商品:

  1. 商家(MyServiceImpl):實際發貨的人
  2. 快遞代收點(Proxy):中間代理點
  3. 代收點規則(InvocationHandler):代收點提供的額外服務(比如驗貨、暫存)

實現步驟詳解

1. 定義服務接口(購物清單)

// 就像網購時商家承諾的服務標準
public interface ShoppingService {void deliverItem();  // 送貨服務String checkQuality(); // 驗貨服務
}

2. 實際商家實現(真實發貨)

public class Amazon implements ShoppingService {@Overridepublic void deliverItem() {System.out.println("亞馬遜發貨中...");}@Overridepublic String checkQuality() {return "正品保障";}
}

3. 創建代收點規則(增值服務)

public class ProxyService implements InvocationHandler {private Object target;  // 真實的商家對象public ProxyService(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 前置增強:代收點驗貨if(method.getName().equals("deliverItem")) {System.out.println("【代收點】快遞消毒中...");}// 執行原方法(讓商家正常發貨)Object result = method.invoke(target, args);// 后置增強:簽收服務if(method.getName().equals("deliverItem")) {System.out.println("【代收點】已簽收,短信通知客戶");}return result;}
}

4. 創建代收點(生成代理)

public class Client {public static void main(String[] args) {// 真實商家ShoppingService amazon = new Amazon();// 創建代理規則InvocationHandler handler = new ProxyService(amazon);// 建立代收點(生成代理實例)ShoppingService proxy = (ShoppingService) Proxy.newProxyInstance(amazon.getClass().getClassLoader(),amazon.getClass().getInterfaces(),handler);// 客戶通過代收點購物proxy.deliverItem();System.out.println("驗貨結果:" + proxy.checkQuality());}
}

輸出結果

【代收點】快遞消毒中...
亞馬遜發貨中...
【代收點】已簽收,短信通知客戶
驗貨結果:正品保障

關鍵點說明

  1. 必須要有接口:就像必須通過電商平臺下單,不能直接找路邊攤
  2. InvocationHandler是核心:所有增強邏輯都在這里實現
  3. Proxy.newProxyInstance三要素
    • 類加載器:用原來的就行
    • 接口數組:說明要代理哪些服務
    • 處理規則:怎么增強這些服務

實際項目應用

在我們電商系統中:

  1. 支付服務接口用JDK代理添加日志
  2. 訂單服務接口用JDK代理添加事務
  3. 商品服務接口用JDK代理做緩存

與CGLIB對比記憶

特性

JDK動態代理

CGLIB

依賴

必須實現接口

不需要接口

原理

實現相同接口

繼承目標類

性能

反射調用稍慢

直接調用更快

適用場景

Spring默認對接口的代理

代理普通類

這樣設計既保持了規范性(面向接口編程),又能靈活添加通用功能。

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

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

相關文章

自然語言處理的相關概念與問題

目錄 一、學科的產生與發展 1、什么是自然語言? 2、自然語言處理技術的誕生 二、技術挑戰 三、基本方法 1、方法概述 理性主義方法 經驗主義方法 2、傳統的統計學習方法 3、深度學習方法 詞向量表示 詞向量學習 開源工具 四、應用舉例 1、漢語分詞 …

Anthropic MCP架構深度解析:下一代AI工具集成協議的設計哲學

本文深入剖析Anthropic提出的模型通信協議(MCP),揭示其如何重構AI與工具生態的交互范式,打造安全高效的智能體基礎設施。 引言:AI工具集成的"巴別塔困境" 當前AI生態面臨的核心挑戰: #mermaid-svg-lSpYBxzxD5oiYwcL {font-family:"trebuchet ms",verd…

【注意】HCIE-Datacom華為數通考試,第四季度將變題!

最近,數據通信圈子可熱鬧壞啦!好幾個渠道都證實了,HCIE - Datacom實驗考試馬上要有大變化咯! 這可不是啥小道消息,也不是那種試點的傳言,而是從IE內部技術交流會上得到的確切消息。 這邊聯系了華為認證的好…

MySql 硬核解析系列 一 MySQL的鎖機制

MySQL 的鎖機制是其并發控制的核心,直接影響數據庫的性能、一致性與可用性。本文將從底層原理、鎖的分類、實現機制、鎖的粒度、鎖的兼容性、死鎖處理、InnoDB 的行鎖實現、MVCC 與鎖的關系等多個維度,進行硬核、深度解析,適用于希望深入理解 MySQL 并發控制機制的開發者與 …

7.軟件工程

軟件生命周期軟件生命周期什么是軟件工程?以工程化的原則和方法來開發軟件,其目的是提高軟件生產率、提高軟件質量、降低軟件成本。軟件工程3大組成部分:方法、工具、過程。什么是軟件生命周期:經過開發、使用和維護,直…

C 語言結構體與 Java 類的異同點深度解析

在編程語言的發展歷程中,C 語言的結構體與 Java 的類扮演著至關重要的角色。作為面向過程編程的經典代表,C 語言的結構體為數據封裝提供了基礎形式;而 Java 作為純面向對象語言,類則是其核心語法結構。二者既存在一脈相承的設計思想,又因編程語言范式的差異呈現出顯著區別…

C++、STL面試題總結(二)

1. 必須實現拷貝構造函數的場景 核心問題:默認拷貝構造的缺陷 C 默認的拷貝構造函數(淺拷貝),會直接拷貝指針 / 引用成員的地址。若類包含引用成員或指向堆內存的指針,淺拷貝會導致 “多個對象共享同一份資源”&…

IntelliJ IDEA2024 錯誤‘http://start.spring.io/‘的初始化失敗,請檢查URL、網絡和代理設置。

下載新版本的intellij idea2024創建項目時,服務器URL報錯誤http://start.spring.io/的初始化失敗,請檢查URL、網絡和代理設置。錯誤消息:Cannot download http://start.spring.io/:Permission denied:getsockopt,具體如下圖&#…

從零開始的云計算生活——第三十八天,避坑落井,Docker容器模塊

一.故事背景 在綜合使用了之前全部的知識完成項目之后,接下來將學習更簡單的方法來對之前的命令進行使用,馬上進入容器模塊 二. Docker概述 Docker簡介 Docker,翻譯過來就是碼頭工人 Docker是一個開源的應用容器引擎,讓開發者…

Python與自動化運維:構建智能IT基礎設施的終極方案

Python與自動化運維:構建智能IT基礎設施的終極方案 引言:運維革命的Python引擎 在DevOps理念席卷全球的今天,企業IT基礎設施的復雜度呈指數級增長。某跨國銀行的數據顯示,采用Python構建的自動化運維體系使其服務器部署效率提升400%,故障響應時間縮短至原來的1/8。本文將…

HarmonyOS應用開發環境搭建以及快速入門介紹

下載并安裝DevEco Studio,這是華為官方提供的HarmonyOS應用開發IDE。訪問華為開發者聯盟官網下載對應操作系統的版本。安裝完成后,配置HarmonyOS SDK和必要的工具鏈。 確保計算機滿足開發環境要求,包括Windows 10 64位或macOS 10.14及以上操…

RocketMQ與Kafka 消費者組的?重平衡操作消息順序性對比

RocketMQ 的重平衡機制本身不會直接影響消息順序,但消費模式的選擇和使用需注意以下細節:重平衡機制RocketMQ消費者組的重平衡策略是每隔20秒從Broker獲取消費組的最新消費進度,并根據訂閱信息重新分配消息隊列。該策略主要影響消息拉取的均衡…

學習 Android(十四)NDK基礎

學習 Android(十四)NDK基礎 Android NDK 是一個工具集,可讓我們使用 C 和 C 等語言以原生代碼實現應用的各個部分。對于特定類型的應用,這可以幫助我們重復使用以這些語言編寫的代碼庫。 接下來,我們將按照以下步驟進行…

寶塔(免費版9.2.0)的docker拉取倉庫失敗的加速方法

寶塔docker拉取倉庫失敗 完美加速方法_寶塔docker加速-CSDN博客 版本:免費版 9.2.0 https://docker.1ms.run 其他的試了很多 都不行 最后不要用寶塔的控制面板(很卡),直接在linux中用命令行,效果就很好了。

文獻解讀-生境分析亞區域選擇+2D_DL+3D_DL-局部晚期食管鱗狀細胞癌新輔助化療免疫治療反應預測

研究標題:結合亞區域放射組學與多通道二維或三維深度學習模型預測局部晚期食管鱗狀細胞癌(LA-ESCC)患者對新輔助化療免疫治療(NACI)的反應借鑒點:建模思路(看流程圖理解就夠了)引言食…

機器學習第四課之決策樹

目錄 簡介 一.決策樹算法簡介 二. 決策樹分類原理 1.ID3算法 1.1 熵值 1.2 信息增益 1.3 案例分析 ?編輯 2.C4.5 2.1 信息增益率 2.2.案例分析 3.CART決策樹 3.1基尼值和基尼指數 3.2案例分析 三、決策樹剪枝 四、決策樹API 五、電信客戶流失 六、回歸樹 七. 回歸…

Java面試題和答案大全

一、Java基礎知識 1. Java語言特點 題目: 請說明Java語言的主要特點? 答案: 面向對象:Java是純面向對象的語言,支持封裝、繼承、多態 平臺無關性:一次編譯,到處運行(Write Once, Run Anywhere) 簡單性:語法簡潔,去掉了C++中的指針、多重繼承等復雜特性 安全性:提…

用NAS如何遠程訪問:詳細教程與實用技巧

在信息時代,家用NAS(網絡附加存儲)成為家庭數據存儲和管理的熱門設備。它不僅可以作為家庭照片、視頻、工作文件的集中存儲中心,還支持遠程訪問,方便用戶隨時隨地獲取數據。那么,如何配置和實現家用NAS的遠…

Qt-桌面寵物

目錄 一,演示(部分功能) 二,開發環境準備 三,部分代碼實現 1.創建基礎窗口 2.實現寵物動畫 3.添加交互功能 4.系統托盤集成 5.行為模式實現 6.狀態管理系統 7.資源打包部署 四,接受定制 一&…

C++編程學習(第19天)

局部變量和全局變量每一個變量都有其有效作用范圍,這就是變量的作用域,在作用域以外是不能訪問這些變量的。局部變量在一個函數內部定義的變量是局部變量,它只在本函數范圍內有效,也就是說只有在本函數內才能使用他們,…