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