JDK 动态代理
一、 了解 JDK 動態代理
1.1 什么是代理模式
在了解動態代理之前,我們有必要先來了解一下什么是代理模式。
代理模式為另一個對象提供一個替身或占位符以控制對這個對象的訪問。使用代理模式創建代表對象,讓代表對象控制某對象的訪問,被代理的對象可以是遠程的對象、創建開銷大的對象或需要安全控制的對象。如下圖:
1.2 什么是 JDK 動態代理
Java 在 java.lang.reflect 包中有自己的代理支持,利用這個包你可以在運行時動態的創建一個代理類,實現一個或多個接口,并將方法的調用轉發到你所指定的類。因為實際的代理類是在運行時創建的,所以稱這個 Java 技術為:動態代理。
1.3 JDK 動態代理 UML 圖解
二、JDK 動態代理具體應用
2.1 問題描述
增強動物叫的功能:在 Animal 接口中定義兩個方法,分別是 cry() 和 eat(),接著定義一些具體的 Animal 類 (比如 Dog、Cat 等),實現其中的方法。要求在不改變原有代碼的基礎上,對每個具體 Animal 對象的 cry() 方法進行增強。
2.2 代碼實現
Animal 接口
package com.jas.jdk.proxy;/*** @author Jas* @create 2018-02-01 9:53**/ public interface Animal {/*** 定義動物叫的方法*/void cry();/*** 定義動物吃的方法*/void eat(); }Dog 類
package com.jas.jdk.proxy;/*** @author Jas* @create 2018-02-01 9:56**/ public class Dog implements Animal {@Overridepublic void cry() {System.out.println("Dog wang wang ...");}@Overridepublic void eat() {System.out.println("Dog eat ...");} }Cat 類
package com.jas.jdk.proxy;/*** @author Jas* @create 2018-02-01 10:39**/ public class Cat implements Animal {@Overridepublic void cry() {System.out.println("Cat miao miao ...");}@Overridepublic void eat() {System.out.println("Cat eat ...");} }OwnerInvocationHandler 類
package com.jas.jdk.proxy;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method;/*** @author Jas* @create 2018-02-01 9:57**/ public class OwnerInvocationHandler implements InvocationHandler {/** 定義被代理的對象*/private Animal animal;/*** 通過構造函數實例化被代理的對象* * @param animal*/public OwnerInvocationHandler(Animal animal){this.animal = animal;}/*** 在 cry 方法執行前后分別打印一句話,其他方法直接執行 * * @param proxy 正在返回的代理對象,一般不怎么使用該對象* @param method 正在被調用的方法* @param args 調用方法時,傳入的參數* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if(("cry").equals(method.getName())){System.out.println("Before animal crying ...");// 執行當前的 cry() 方法Object object = method.invoke(animal, args);System.out.println("After animal crying ...");return object;}/*** 如果調用的是其他方法,則直接執行*/return method.invoke(animal, args); } }AnimalProxy 類
package com.jas.jdk.proxy;import java.lang.reflect.Proxy;/*** @author Jas* @create 2018-02-01 10:03**/ public class AnimalProxy {/*** 返回代理對象* * @param animal* @return*/public Animal getAnimal(Animal animal){/*** newProxyInstance() 方法有三個參數* * newProxyInstance(ClassLoader loader, -> 表示加載這個類的類加載器* Class<?>[] interfaces, -> 代理類實現的接口方法列表* InvocationHandler h) -> InvocationHandler 控制對真實對象方法的訪問*/return (Animal) Proxy.newProxyInstance(animal.getClass().getClassLoader(), animal.getClass().getInterfaces(), new OwnerInvocationHandler(animal));} }測試類
package com.jas.jdk.proxy;/*** @author Jas* @create 2018-02-01 10:05**/ public class AnimalTestDrive {public static void main(String[] args) {Animal dog = new AnimalProxy().getAnimal(new Dog());Animal cat = new AnimalProxy().getAnimal(new Cat());dog.cry();dog.eat();System.out.println("================");cat.cry();cat.eat();//可以判斷當前對象是不是代理類,如果是返回 true ,不是返回 falseSystem.out.println(Proxy.isProxyClass(dog.getClass()));}}輸出
Before animal crying ... Dog wang wang ... After animal crying ... Dog eat ... ================ Before animal crying ... Cat miao miao ... After animal crying ... Cat eat ... true三、JDK 動態代理模式總結
3.1 JDK 動態模式知識點總結與注意事項
- 當你需要對一個接口的實現進行功能增強,又不想修改原有的代碼時,你可以選擇使用 JDK 動態代理模式。
- 可以通過 isProxyClass() 方法判斷一個類是不是代理類,除此之外,代理類還會實現特定的接口。
- 動態代理之所以被稱為動態,是因為運行時才將它的類創建出來。代碼開始執行時還沒有 proxy 類,它是根據需要從你傳入的接口集創建的。
- InvocationHandler 本身不是 proxy,它只是一個幫助 proxy 的類,proxy 會把對方法的調用轉發給它。Proxy 本身是通過 Proxy.newProxyInstance() 方法在運行時動態創建的。
PS:點擊了解更多設計模式 http://blog.csdn.net/codejas/article/details/79236013
參考資料
《Head First 設計模式》
總結
- 上一篇: Java 设计模式之状态模式
- 下一篇: MyBtis快速入门