1 代理模式(Proxy)
代理模式的基本介紹
1) 代理模式:為一個物件提供一個替身,以控制對這個物件的訪問,即通過代理物件訪問目標物件.這樣做的好處是:可以在目標物件實作的基礎上,增強額外的功能操作,即擴展目標物件的功能,
2) 被代理的物件可以是遠程物件、創建開銷大的物件或需要安全控制的物件
3) 代理模式有不同的形式, 主要有三種 靜態代理、動態代理 (JDK 代理、介面代理)和 Cglib 代理 (可以在記憶體動態的創建物件,而不需要實作介面, 他是屬于動態代理的范疇) ,
4) 代理模式示意圖
2 靜態代理
2.1 靜態代碼模式的基本介紹
靜態代理在使用時,需要定義介面或者父類,被代理物件(即目標物件)與代理物件一起實作相同的介面或者是繼承相同父類
2.2 應用實體
具體要求
1) 定義一個介面:ITeacherDao
2) 目標物件 TeacherDAO 實作介面 ITeacherDAO
3) 使用靜態代理方式,就需要在代理物件 TeacherDAOProxy 中也實作 ITeacherDAO
4) 呼叫的時候通過呼叫代理物件的方法來呼叫目標物件.
5) 特別提醒:代理物件與目標物件要實作相同的介面,然后通過呼叫相同的方法來呼叫目標物件的方法
思路分析圖解(類圖)

package com.lin.proxy; public interface ITeacherDao { void teach(); }
package com.lin.proxy; public class TeacherDao implements ITeacherDao{ @Override public void teach() { System.out.println("老師正在授課中...."); } }
package com.lin.proxy; /* * 靜態代理 * 代理物件 */ public class TeacherDaoProxy implements ITeacherDao{ private ITeacherDao teacherDao = null; public TeacherDaoProxy(ITeacherDao teacherDao) { this.teacherDao = teacherDao; } @Override public void teach() { System.out.println("代理開始"); System.out.println("準備授課的作業"); teacherDao.teach(); System.out.println("代理結束"); } }
package com.lin.proxy; public class Client { public static void main(String[] args) { TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(new TeacherDao()); teacherDaoProxy.teach(); } }
2.3 靜態代理優缺點
1) 優點:在不修改目標物件的功能前提下, 能通過代理物件對目標功能擴展
2) 缺點:因為代理物件需要與目標物件實作一樣的介面,所以會有很多代理類
3) 一旦介面增加方法,目標物件與代理物件都要維護
3 動態代理
3.1 動態代理模式的基本介紹
1) 代理物件,不需要實作介面,但是目標物件要實作介面,否則不能用動態代理
2) 代理物件的生成,是利用 JDK 的 API,動態的在記憶體中構建代理物件
3) 動態代理也叫做:JDK 代理、介面代理
3.2 JDK 中生成代理物件的 API
1) 代理類所在包:java.lang.reflect.Proxy
2) JDK 實作代理只需要使用 newProxyInstance 方法,但是該方法需要接收三個引數,完整的寫法是:
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
3.3 動態代理應用實體
應用實體要求
將前面的靜態代理改進成動態代理模式(即:JDK 代理模式)
思路圖解(類圖)

package com.lin.proxy.dynamic; public interface ITeacherDao { void teach(); }
package com.lin.proxy.dynamic; public class TeacherDao implements ITeacherDao{ @Override public void teach() { System.out.println("老師正在授課中...."); } }
package com.lin.proxy.dynamic; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyFactory{ private Object target; public ProxyFactory(Object target) { this.target = target; } // 給目標物件生成一個代理物件 public Object getProxyInstance() { /* * ClassLoader loader, * Class<?>[] interfaces, * InvocationHandler h * 1 ClassLoader loader:指定目標對像是要的類加載器,獲取加載器的方法固定 * 2 Class<?>[] interfaces:目標物件實作的介面型別,是要泛型方法確認型別 * 3 InvocationHandler h:事情處理,執行目標物件的方法時,會觸發事情處理器方法,會把當前 * 執行的目標物件作為引數傳入 */ return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("JDK代理開始"); // 利用反射機制呼叫目標物件的方法 Object returnVal = method.invoke(target, args); return returnVal; } } ); } }
package com.lin.proxy.dynamic; public class Client { public static void main(String[] args) { ITeacherDao target = new TeacherDao(); ITeacherDao proxyInstance = (ITeacherDao)new ProxyFactory(target).getProxyInstance(); System.out.println(proxyInstance.getClass()); proxyInstance.teach(); } }
4 Cglib 代理
4.1 Cglib 代理模式的基本介紹
1) 靜態代理和 JDK 代理模式都要求目標物件是實作一個介面,但是有時候目標物件只是一個單獨的物件,并沒有實作任何的介面,這個時候可使用目標物件子類來實作代理-這就是 Cglib 代理
2) Cglib 代理也叫作子類代理,它是在記憶體中構建一個子類物件從而實作對目標物件功能擴展, 有些書也將Cglib 代理歸屬到動態代理,
3) Cglib 是一個強大的高性能的代碼生成包,它可以在運行期擴展 java 類與實作 java 介面.它廣泛的被許多 AOP 的框架使用,例如 Spring AOP,實作方法攔截
4) 在 AOP 編程中如何選擇代理模式:
- 目標物件需要實作介面,用 JDK 代理
- 目標物件不需要實作介面,用 Cglib 代理
5) Cglib 包的底層是通過使用位元組碼處理框架 ASM 來轉換位元組碼并生成新的類
4.2 Cglib 代理模式實作步驟
1)需要引入 cglib 的 jar 檔案
2)在記憶體中動態構建子類,注意代理的類不能為 final,否則報錯java.lang.IllegalArgumentException:
3) 目標物件的方法如果為 final/static,那么就不會被攔截,即不會執行目標物件額外的業務方法.
15.1.1 Cglib 代理模式應用實體
應用實體要求
將前面的案例用 Cglib 代理模式實作
思路圖解(類圖)

package com.lin.proxy.cglib; public class TeacherDao{ public void teach() { System.out.println("老師正在授課中...."); } }
package com.lin.proxy.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class ProxyFactory implements MethodInterceptor{ // 維護一個目標物件 private Object target = null; public ProxyFactory(Object target) { this.target = target; } // 回傳一個代理物件,是target物件的代理物件 public Object getProxyInstance() { /* * 1 創建一個工具類 * 2 設定父類 * 3 設定回呼函式 * 4 創建子類物件,即代理物件 */ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] objs, MethodProxy methodProxy) throws Throwable { System.out.println("cglib代理模式開始"); Object invoke = method.invoke(target, objs); System.out.println("cglib代理模式結束"); return invoke; } }
package com.lin.proxy.cglib; public class Client { public static void main(String[] args) { TeacherDao teacherDao = new TeacherDao(); TeacherDao proxyFactory = (TeacherDao)new ProxyFactory(teacherDao).getProxyInstance(); proxyFactory.teach(); } }
5 幾種常見的代理模式介紹— 幾種變體
1) 防火墻代理
內網通過代理穿透防火墻,實作對公網的訪問,
2) 快取代理
比如:當請求圖片檔案等資源時,先到快取代理取,如果取到資源則 ok,如果取不到資源,再到公網或者資料庫取,然后快取,
3) 遠程代理
遠程物件的本地代表,通過它可以把遠程物件當本地物件來呼叫,遠程代理通過網路和真正的遠程物件溝通資訊,
4) 同步代理:主要使用在多執行緒編程中,完成多執行緒間同步作業同步代理:主要使用在多執行緒編程中,完成多執行緒間同步作業
僅供參考,有錯誤還請指出!
有什么想法,評論區留言,互相指教指教,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/257014.html
標籤:Java
上一篇:設計模式(十二)——享元模式(Integer緩沖池原始碼分析)
下一篇:Spring常用注解
