1. 概述
動態代理 是指在運行時,動態地創建目標類的代理對象,并對其中特定的方法進行攔截或增強的技術。這種技術主要用于在不修改目標類代碼的情況下,增強目標類的功能。?
在Java中,動態代理主要基于Java的反射機制和接口來實現。當一個類實現了某個接口,并且需要在不修改這個類代碼的前提下增加一些新的方法或者對原有方法進行一些處理(比如添加日志、事務管理、權限校驗等),就可以使用動態代理來實現。即它可以無侵入式的修改代碼。
2. 講故事
為了方便理解,我這里舉一個生活中的故事吧,前不久報名了微軟云的認證考試,報名之后前往考點,我才發現這個考點其實根本就不是微軟公司親自設立的,而是有其他公司代理的,因為微軟雖大,但是不可能在世界每一個城市都親自設立辦公處或者說是認證考點吧。這種情況下微軟就需要請其他公司代理。幫他管理考試過程。那么微軟和代理公司在這個過程中分別做了什么呢?
首先是代理公司:
- 代理公司需要提供考點
- 當考生到了考點后,大代理公司的工作人員,需要對參考的考生進行檢查確認考生沒有夾帶或使用作弊工具
- 代理公司需要查詢考生證件,確包是考生本人,而不是代考
- 代理公司需要對考生全身照和寸照,用于給微軟公司證明考生無夾帶,以及將寸照傳入電子證書上。
- 代理公司需要提供考試電腦,并幫助考試宣講考試步驟,考試過程攝像。教考試如何遠程獲取使用微軟考題。
- 代理公司維持考場秩序
- 如果考生考過了,代理公司需要打印微軟發送的證書,發給考生。
而微軟做了什么呢:
- 管理考生報名
- 網上收取考生考試費用
- 考試時遠程提供題庫
- 遠程發送證書
通過上面我們可以看到,代理給微軟節省了很多成本,也省了很多事,而代理公司通過這個過程也可以做一個兼職賺了一筆外快。是一個雙贏的局面。生活中這樣的例子有很多。
所以我們程序里面的動態代理,可以有很多類似的效果,為我們程序員減少重復代碼,提高擴展性等都很有用處。
3.動態代理的實現步驟如下:
- 定義接口:首先定義一個接口,這個接口定義了目標類需要實現的方法。
package com.mycompany.proxyreflection2;public interface ExamServer {String examAz900();String examAz700(); }
- 實現目標類:創建一個類實現上述接口,這個類就是目標類。
package com.mycompany.proxyreflection2;public class TargetCompanyExamServerImpl implements ExamServer {@Overridepublic String examAz900() {return "This is microsoft, wlc exam azure 900, transfer the question bank to proxy";}@Overridepublic String examAz700() {return "This is microsoft, wlc exam azure 700, transfer the question bank to proxy";} }
- 創建InvocationHandler:創建一個實現了InvocationHandler接口的類,這個類將負責攔截并處理對目標類方法的調用。
package com.mycompany.proxyreflection2;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method;public class ProxyCompanyInvocationHandler implements InvocationHandler {private final Object target; // 目標對象 舉例中的微軟對象public ProxyCompanyInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 在調用目標方法之前執行一些操作(例如日志記錄)System.out.println("代理公司需要提供考點");System.out.println("當考生到了考點后,大代理公司的工作人員,需要對參考的考生進行檢查確認考生沒有夾帶或使用作弊工具");System.out.println("代理公司需要查詢考生證件,確包是考生本人,而不是代考");System.out.println("代理公司需要對考生全身照和寸照,用于給微軟公司證明考生無夾帶,以及、便將寸照傳入電子證書上。");System.out.println("代理公司需要提供考試電腦,并幫助考試宣講考試步驟,考試過程攝像。教考試如何遠程獲取使用微軟考題。");// 調用目標對象上的方法, 獲取微軟考題Object result = method.invoke(target, args);System.out.println(result);// 在調用目標方法之后執行一些操作(例如日志記錄)System.out.println("代理公司維持考場秩序");System.out.println("如果考生考過了,代理公司需要打印微軟發送的證書,發給考生。");return result;} }
- 創建代理對象:使用Proxy類的newProxyInstance方法,傳入目標類的類加載器、目標類實現的接口列表以及InvocationHandler實例,來創建代理對象。
package com.mycompany.proxyreflection2;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy;public class ProxyCompany {public static <T> T createProxy(T target) {// 獲取目標對象的類加載器和接口類型ClassLoader classLoader = target.getClass().getClassLoader();Class<?>[] interfaces = target.getClass().getInterfaces();// 創建一個 InvocationHandler 實例InvocationHandler handler = new ProxyCompanyInvocationHandler(target);// 使用 Proxy 類的靜態方法 newProxyInstance 創建代理對象T proxy = (T) Proxy.newProxyInstance(classLoader, interfaces, handler);return proxy;} }
- 調用方法:通過代理對象調用目標類的方法時,會首先被InvocationHandler的invoke方法攔截,可以在這個方法中添加額外的處理邏輯,然后再調用目標類的方法。
package com.mycompany.proxyreflection2;public class ExamApi {public static void main(String[] args) {// 創建一個 ExamServer 的實現類實例ExamServer myService = new TargetCompanyExamServerImpl();// 使用 ProxyFactory 創建一個 ExamServer 的代理實例ExamServer proxyService = ProxyCompany.createProxy(myService);// 調用代理實例上的方法System.out.println("-----------------Start proxy exam Az 700----------------");proxyService.examAz700();System.out.println("-----------------Start proxy exam Az 900----------------");proxyService.examAz900();} }
運行結果:
-----------------Start proxy exam Az 700----------------
代理公司需要提供考點
當考生到了考點后,大代理公司的工作人員,需要對參考的考生進行檢查確認考生沒有夾帶或使用作弊工具
代理公司需要查詢考生證件,確包是考生本人,而不是代考
代理公司需要對考生全身照和寸照,用于給微軟公司證明考生無夾帶,以及、便將寸照傳入電子證書上。
代理公司需要提供考試電腦,并幫助考試宣講考試步驟,考試過程攝像。教考試如何遠程獲取使用微軟考題。
This is microsoft, wlc exam azure 700, transfer the question bank to proxy
代理公司維持考場秩序
如果考生考過了,代理公司需要打印微軟發送的證書,發給考生。
-----------------Start proxy exam Az 900----------------
代理公司需要提供考點
當考生到了考點后,大代理公司的工作人員,需要對參考的考生進行檢查確認考生沒有夾帶或使用作弊工具
代理公司需要查詢考生證件,確包是考生本人,而不是代考
代理公司需要對考生全身照和寸照,用于給微軟公司證明考生無夾帶,以及、便將寸照傳入電子證書上。
代理公司需要提供考試電腦,并幫助考試宣講考試步驟,考試過程攝像。教考試如何遠程獲取使用微軟考題。
This is microsoft, wlc exam azure 900, transfer the question bank to proxy
代理公司維持考場秩序
如果考生考過了,代理公司需要打印微軟發送的證書,發給考生。?
這種方式的優點是可以在不修改目標類代碼的情況下增加新的功能,提高了系統的靈活性和可擴展性。但是,由于Java的動態代理是基于接口的,所以目標類必須實現一個或多個接口,否則無法使用動態代理。