1. 程式人生 > >Java-JDK動態代理(AOP)使用及實現原理分析

Java-JDK動態代理(AOP)使用及實現原理分析

# Java-JDK動態代理(AOP)使用及實現原理分析 # 第一章:代理的介紹 介紹:我們需要掌握的程度 > 動態代理(理解) 基於反射機制 掌握的程度: 1.什麼是動態代理? 2.動態代理能夠做什麼? 後面我們在用Spirng和Mybatis的時候,要理解怎麼使用的. ## 1.什麼是代理? 代理,在我們日常生活之中就有體現,代購,中介,換ip,商家等等. 比如有一家美國的大學,可以對全世界招生.留學中介(代理 ) 留學中介(代理):幫助這家美國的學校招生,中介是學校的代理中介是代替學校完成招生功能 代理特點 1. 中介和代理他們要做的事情是一致的:招生 2. 中介是學校代理,學校是目標 3. 家長-------->中介(學校介紹,辦理入學手續)---------->美國學校 4. 中介是代理,收取費用 ## 2.為什麼要找中介 為什麼要找中介? 1.中介是專業的,方便. 2.家長現在不能自己去找學校。家長沒有能力訪問學校.或者美國學校不接收個人來訪 買東西都是商家賣, 商家是某個商品的代理, 你個人買東西,肯定不會讓你接觸到廠家的. # 第二章:靜態代理 ![](https://img2020.cnblogs.com/blog/1448883/202010/1448883-20201013211911489-1288739271.png) ## 2.1 使用代理模式的作用 1. 功能增強:在你原有的功能上,增加了額外的功能.新增加的功能,叫做功能增強 2. 控制訪問:代理類不讓你訪問目標,例如商家不讓使用者訪問廠家 ## 2.2 實現代理的方式 1.靜態代理: 1)代理類是自己手工實現的,自己建立一個java類,表示代理類 2)同時你所要代理的目標 特點:1)實現簡單2)容易理解。 模擬一個使用者購買u盤的行為。 使用者是客戶端類 商家:代理,代理某個品牌的u盤。 廠家:目標類。 三者的關係:使用者(客戶端)-—-商家(代理)-—-廠家(目標) 商家和廠家都是賣u盤的,他們完成的功能是一致的,都是賣u盤。 > 實現步驟: 實現步驟 1.建立一個介面,定義賣u盤的方法,表示你的廠家和商家做的事情 2.創建廠家類,實現1步驟的介面 3.建立商家,就是代理,也需要實現1步驟中的介面 4.建立客戶端類,呼叫商家的方法買一個u盤 ## 2.3 具體實現 ![](https://img2020.cnblogs.com/blog/1448883/202010/1448883-20201013212037763-124310641.png) 實現步驟 1.建立一個介面,定義賣u盤的方法,表示你的廠家和商家做的事情 ```java package com.rango.service; public interface usbSell { /** * 定義一個方法 引數 amount:表示一次購買的數量,暫時不用 * 返回值表示一個u盤的價格 * @param amount * @return */ float sell(int amount); } ``` 2.創建廠家類,實現1步驟的介面 ```java package com.rango.factory; import com.rango.service.usbSell; //目標類:金士頓廠家,不接受使用者的單獨購買 public class UsbKingFactory implements usbSell { /** * 定義一個方法 引數 amount:表示一次購買的數量,暫時不用 * 返回值表示一個u盤的價格 * * @param amount * @return */ @Override //一個128G的U盤是85元. // 後期根據amount,可以實現不同的價格,例如10000個,單擊是80,50000個75 public float sell(int amount) { return 85.0f*amount; } } ``` 3.建立商家,就是代理,也需要實現1步驟中的介面 ```java package com.rango.business; import com.rango.factory.UsbKingFactory; import com.rango.service.usbSell; //淘寶是一個商家,代理金士頓U盤的銷售 public class TaoBao implements usbSell { // 宣告 商家代理的廠家具體是誰 private UsbKingFactory factory =new UsbKingFactory(); @Override // 實現銷售U盤功能 public float sell(int amount) { // 向廠家傳送訂單,告訴廠家,我買了U盤,廠家發貨 // 傳送給工廠,我需要的訂單,返回報價 float price = factory.sell(amount); // 商家需要加價也就是代理要增加價格 price = price + 25; //在目標類的方法呼叫後,你做的其他功能,都是增強的意思 System.out.println("淘寶再給你返回一個優惠券,或者紅包"); // 增加的價格 return price; } } ``` 4.建立客戶端類,呼叫商家的方法買一個u盤 ```java import com.rango.business.TaoBao; public class shopMain { public static void main(String[] args){ // 建立代理的商家淘寶物件 TaoBao taoBao = new TaoBao(); // 我只向淘寶買一件產品,得到報價 float price = taoBao.sell(2); System.out.println("購買一件產品.淘寶的報價為: "+price); } } ``` > 所以我們再次總結代理類完成的功能: > > 1. 目標類中方法的呼叫 > 2. 功能增強 所屬我們只有一個代理商,我們實際上可以寫多個代理商, ## 2.4 靜態代理的優缺點 我們再次總結一下靜態代理的優缺點 優點: 1. 實現簡單 2. 容易簡單 確定:當你的專案中,目標類的代理類很多的時候,有一下的缺點 1. 當目標類增加了,代理類可能也需要成倍的增加 2. 當你的介面中功能在增加了,或者修改了,會影響眾多的實現類,廠家類,代理都需要修改,影響比較多. 所以我們繼續學習動態代理 # 第三章 動態代理 本章,我們所掌握的是 1)什麼是動態代理? ​ 使用jdk的反射機制,建立物件的能力,建立的是代理類的的物件.而不用我們建立類檔案,不用寫java檔案, 什麼叫動態?在程式執行時,呼叫jdk提供的方法才能建立代理類的物件 ![](https://img2020.cnblogs.com/blog/1448883/202010/1448883-20201013212110331-1121695877.png) 2)知道動態代理能做什麼? ## 2.1 靜態代理和動態代理模式的對比 > 在靜態代理中目標很多的時候,可以使用動態代理,避免靜態代理的缺點 在靜態代理中目標類很多時候,可以使用動態代理,避免靜態代理的缺點。 動態代理中目標類即使很多, 1. 代理類數量可以很少, 2. 當你修改了介面中的方法時,不會影響代理類。 動態代理:在程式執行過程中,使用jdk的反射機制,建立代理類物件,並動態的指定要代理目標類。 換句話說:動態代理是一種建立java象的能力,讓你不用建立 TaoBao類就能建立代理類物件,除去了中間商 在java中,要想建立物件 1. 建立類檔案,java 檔案編譯為class 2. 使用構造方法,建立類的物件 ## 2.1 動態代理的介紹 ![](https://img2020.cnblogs.com/blog/1448883/202010/1448883-20201013212134218-151624166.png) 1. 動態代理是指代理類物件在程式執行時由JVM根據反射機制動態生成的。動態代理不需要定義代理類的,java原始檔。 2. 動態代理其實就是jdk執行期間,動態建立class位元組碼並載入到JVM。 3. 動態代理的實現方式常用的有兩種:使用JDK代理,與通過CGLlB動態代理。 動態代理的實現: > 1. jdk動態代理(理解):使用java反射包中的類和介面實現動態代理的功能,反射包java.lang.reflect,裡面有三個類:InvocationHandler,Method,Proxy > 2. cglib動態代理(瞭解): cglib是第三方的工具庫,建立代理物件 > 1. cglib的原理是繼承,cglib通過繼承目標類,建立它的子類,在子類中 > 重寫父類中同名的方法,實現功能的修改。 > 2. 因為cglib是繼承,重寫方法,所以要求目標類不能是fina1的,方法也不能是final的。cglib的要求目標類比較寬鬆,只要能繼承就可以了。cglib在很多的框架中使用, > 比如mybatis,spring框架中都有使用。 ![](https://img2020.cnblogs.com/blog/1448883/202010/1448883-20201013212148206-1699340545.png) ```java package Test; import com.rango.Impl.HelloServiceImpl; import com.rango.service.HelloService; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class TestApp { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { // HelloService service = new HelloServiceImpl(); // service.sayhello("張三"); // 以上是常規方法執行sayhello // 下面我們使用反射機制進行建立sayhello方法,核心Method(類中的方法) HelloServiceImpl target = new HelloServiceImpl(); // 獲取sayhello名稱對應的Method類物件 // public Method getM ethod(String name, Class... parameterTypes) // 加入,該方法的引數有多個該怎麼辦? // parameterTypes引數是一個類物件陣列,按宣告的順序標識方法的形式引數型別。 Method method = HelloService.class.getMethod("sayhello", String.class); // 通過Metho可以執行sayhello方法的呼叫 /* * public Object invoke(Object obj, Object... args) * 表示執行方法的呼叫 * 引數: * 1.Object,表示物件,要執行這個物件的方法 * 2.Object...args,方法執行時的引數值 * 返回值: * Object:方法執行後的返回值 * */ Object ret = method.invoke(target, "李四"); } } ``` ## 2.2 回顧反射 Method類 > Method類的結構圖 > > - Class Method > - java.lang.Object > - java.lang.reflect.AccessibleObject > - java.lang.reflect.Executable > - java.lang.reflect.Method ### 2.2.1 class.getMethod > ```java > Method method = HelloService.class.getMethod("sayhello", String.class,Integer.class); > ``` 提出問題? ```java public Method getMethod(String name, Class... parameterTypes) ``` 加入,該方法的引數有多個該怎麼辦? parameterTypes引數是一個類物件陣列,按宣告的順序標識方法的形式引數型別。 ### 2.2.2 Method.invoke `public Object invoke(Object obj,Object... args)` ```java * public Object invoke(Object obj, Object... args) * 表示執行方法的呼叫 * 引數: * 1.Object,表示物件,要執行這個物件的方法 * 2.Object...args,方法執行時的引數值 * 返回值: * Object:方法執行後的返回值 * ``` ## 2.3 JDK動