摘要:設計模式之代理模式今天學到的動態代理實現,對代理這個概念很模糊,看了一篇文章發現這是一種設計模式,于是學習記錄一下。簡介代理模式是一種對象結構型的模式,主要為其他對象提供一種代理以控制對這個對象的訪問。下面依次講解著三種代理。
設計模式之代理模式
今天學到Spring的動態代理實現AOP,對代理這個概念很模糊,看了一篇文章發現這是一種設計模式,于是學習記錄一下。
簡介代理模式是一種對象結構型的模式,主要為其他對象提供一種代理以控制對這個對象的訪問。簡單點說就是你訪問一個對象并不是直接的訪問它,而是通過一個代理簡介訪問,那么這個代理就可以在訪問對象之前或之后做一些定制化的操作,比如校驗入參,打印日志什么的。Spring AOP就是一個代理模式的典型應用。
java中的代理分為三類:靜態代理、動態代理和Cglib代理。下面依次講解著三種代理。
1. 靜態代理靜態代理在使用時,需要定義接口或者父類,被代理的對象和代理對象需要一起實現同一個接口或者繼承同一個父類。
代碼示例
接口:
package com.wangjun.designPattern.proxy; /* * 我們有一個人類的接口,有很多種職業,比如教師,學生 */ public interface Person { //獲取本職業的職責 public String getDuty(); }
目標對象1:
package com.wangjun.designPattern.proxy; public class Student implements Person { @Override public String getDuty() { return "學習知識"; } }
目標對象2:
package com.wangjun.designPattern.proxy; public class Teacher implements Person { @Override public String getDuty() { return "教書育人"; } }
代理對象:
package com.wangjun.designPattern.proxy; import java.util.HashMap; import java.util.Map; /* * 通過代理,加入緩存功能 */ public class CachedPersonProxy implements Person{ private Person person; private Mapmap = new HashMap<>();; public CachedPersonProxy(Person person) { this.person = person; } @Override public String getDuty() { String duty = map.get(person); if(null == duty) { duty = person.getDuty(); map.put(person, duty); } return duty; } }
測試類:
package com.wangjun.designPattern.proxy; public class Main { public static void main(String[] args) { Teacher teacher = new Teacher(); CachedPersonProxy proxy = new CachedPersonProxy(teacher); System.out.println(proxy.getDuty()); } }
靜態代理總結:
優點:可以做到在不修改目標對象的功能前提下,對目標功能擴展;
缺點:因為代理對象需要與目標對象實現一樣的接口,所以會有很多代理類,同時,一旦接口增加方法,目標對象與代理對象都要維護。
2. 動態代理動態代理也叫JDK代理或者接口代理。
動態代理有以下特點:
代理對象不需要實現接口;
代理對象的生成是利用JDK中的API動態的在內存中構建代理對象(需要我們指定創建代理對象/目標對象實現的接口的類型);
代理類所在的包是:java.lang.reflect.Proxy
JDK實現動態代理只需要使用newProxyInstance方法,該方法需要傳入三個變量:
public static Object newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h) throws IllegalArgumentException
ClassLoader loader:指定當前目標對象使用類加載器,獲取加載器的方法是固定的
Class>[] interfaces:目標對象實現的接口的類型,使用泛型方式確認類型
InvocationHandler h:事件處理,執行目標對象的方法時,會觸發事件處理器的方法,會把當前執行目標對象的方法作為參數傳入。
代碼示例
接口類Person.class和實現類Teacher.class、Sutdent.class不變,在這個基礎上,增加一個代理工廠類ProxyFactory.java,然后在測試類(需要使用到代理的代碼)中先建立目標對象和代理對象的聯系,接著代用代理對象的中同名方法。
代理工廠類:
package com.wangjun.designPattern.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.Map; public class ProxyFactory { private Person person; private Mapmap = new HashMap<>(); public ProxyFactory(Person person) { this.person = person; } public Object getProxyInstance() { return Proxy.newProxyInstance( person.getClass().getClassLoader(), person.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String duty = map.get(person); if(null == duty) { //執行對象方法 System.out.println("沒有緩存"); duty = (String) method.invoke(person, args); map.put(person, duty); } return duty; } }); } }
測試類:
package com.wangjun.designPattern.proxy; public class Main { public static void main(String[] args) { Person teacher = new Teacher(); System.out.println(teacher.getClass()); //使用動態代理 ProxyFactory proxyFactory = new ProxyFactory(teacher); Person teacherProxy = (Person) proxyFactory.getProxyInstance(); System.out.println(teacherProxy.getClass()); System.out.println(teacherProxy.getDuty()); System.out.println(teacherProxy.getDuty()); } }
總結
代理對象不需要實現接口,但是目標對象一定要實現接口,否則不能用動態代理。
3. Cglib代理上面的靜態代理和動態代理模式都是要求目標對象是實現一個接口的目標對象,但是有時候目標對象只是一個多帶帶的對象,并沒有實現任何的接口,這個時候就可以使用以目標對象子類的方式類實現代理,這種方法就叫做:Cglib代理。
Cglib是一個強大的,高性能,高質量的Code生成類庫,它可以在運行期擴展Java類與實現Java接口。它廣泛的被許多AOP的框架使用,例如Spring AOP和synaop,為他們提供方法的interception(攔截)。
Cglib代理,也叫作子類代理,它是在內存中構建一個子類對象從而實現對目標對象功能的擴展。
Cglib包的底層是通過使用一個小而塊的字節碼處理框架ASM來轉換字節碼并生成新的類。不鼓勵直接使用ASM,因為它要求你必須對JVM內部結構包括class文件的格式和指令集都很熟悉。
Cglib子類實現代理的方法
需要引入cglib和asm的jar包文件,Spring的核心包里面已經包含了此包;
引入jar包后,就可以在內存中動態構建子類;
代理的類不能為final,否則報錯;
目標對象的方法如果為final/static,那么就不會被攔截,即不會執行目標對象額外的方法。
代碼示例
目標對象類:
package com.wangjun.designPattern.proxy; /* * 目標對象,沒有實現任何接口 */ public class Doctor { public String getDuty() { return "救死扶傷"; } }
Cglib代理工廠類:
package com.wangjun.designPattern.proxy; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /* * cglib代理工廠 * 對Doctor在內存中動態構建一個子類對象 */ public class CglibProxyFactory implements MethodInterceptor { private Object person; private Map
測試類:
package com.wangjun.designPattern.proxy; public class Main { public static void main(String[] args) { // 使用cglib // 目標對象 Doctor target = new Doctor(); System.out.println(target.getClass()); // 代理對象 Doctor proxyCglib = (Doctor) new CglibProxyFactory(target).getProxyInstance(); // 執行代理對象的方法 System.out.println(proxyCglib.getClass()); System.out.println(proxyCglib.getDuty()); System.out.println(proxyCglib.getDuty()); } }
在Spring的AOP編程中:
如果加入容器的目標對象有實現接口,用JDK代理
如果目標對象沒有實現接口,用Cglib代理
參考:https://www.cnblogs.com/cenyu/p/6289209.html
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69278.html
摘要:面向對象設計里的設計模式之代理模式,相信很多朋友已經很熟悉了。代表當前執行方法的實例,即方法調用者。代表具體的方法名稱?,F在我們再次調用,傳入構造器返回的代理對象打印輸出,代理邏輯生效了和的一樣優雅地實現了代理設計模式。 showImg(https://segmentfault.com/img/remote/1460000016760603);面向對象設計里的設計模式之Proxy(代理...
摘要:簡述從這篇文章起,我們將繼續邂逅設計模式系列篇中的第二篇代理模式。代理模式可以說很多初級中級開發者迷惑的設計模式。首先我們需要使用類圖直觀地表示出代理模式思想。所以基于代理模式很輕松就實現。簡述: 從這篇文章起,我們將繼續Kotlin邂逅設計模式系列篇中的第二篇代理模式。代理模式可以說很多初級中級開發者迷惑的設計模式。但是它確實應用很廣,不用多說大家非常熟悉的Retrofit框架,內部使用了...
摘要:場景描述病從口入這句成語告訴我們注意飲食健康,小六同學想吃蘋果,在吃蘋果之前需要清洗一下蘋果和洗一下手,吃完蘋果后,需要洗一下手保持個人衛生十分鐘后。。。動態代理小六委托管家來代理洗食物和洗手,小六屬于委托對象,管家屬于代理對象。 前言 為了更好的理解代理模式,首先根據生活中實際場景進行模擬,讓我們在生活中去體驗設計思想的美妙。 場景描述 病從口入這句成語告訴我們注意飲食健康,小六同學...
時間:2017年08月28日星期一說明:本文部分內容均來自慕課網。@慕課網:http://www.imooc.com教學源碼:https://github.com/zccodere/s...學習源碼:https://github.com/zccodere/s... 第一章:代理模式 1-1 概念介紹 學習本課程基礎 面向對象的設計思維 了解多態的概念 了解反射機制 課程目標 代理模式基本概念及分類...
閱讀 1439·2021-09-03 10:29
閱讀 3463·2019-08-29 16:24
閱讀 2023·2019-08-29 11:03
閱讀 1416·2019-08-26 13:52
閱讀 2930·2019-08-26 11:36
閱讀 2793·2019-08-23 17:19
閱讀 565·2019-08-23 17:14
閱讀 813·2019-08-23 13:59