java設計優(yōu)化之代理模式
代理模式使用代理對象完成用戶的請求,屏蔽用戶對真實對象的訪問。
代理模式的用途很多,比如因為安全原因,需要屏蔽客戶端直接訪問真實對象;或者在遠程調(diào)用中,需要使用代理對象處理遠程方法中的技術細節(jié);或者為了提升系統(tǒng),對真是對象進行封裝,從而達到延遲加載的目的。
在系統(tǒng)啟動時,將消耗資源最多的方法使用代理模式分離,就可以加快系統(tǒng)的啟動速度,減少用戶的等待時間。在用戶真正在做查詢是,再由代理類加載真實的類,完成用戶請求。這就是使用代理模式達到延遲加載的目的。
1.靜態(tài)代理實現(xiàn):
主題接口:
public interface IDBQuery { String request(); }
真實主題:
public class DBQuery implements IDBQuery { public DBQuery(){ try { Thread.sleep(10000); } catch (Exception e) { e.printStackTrace(); } } public String request() { return "string request"; } }
代理類:
public class IDBQueryProxy implements IDBQuery { private DBQuery dbquery; public String request() { if(dbquery==null) dbquery = new DBQuery(); return dbquery.request(); } }
最后,主函數(shù):
public class ProxyText { public static void main(String[] args) { IDBQuery dbquery = new IDBQueryProxy(); System.out.println(dbquery.request()); } }
靜態(tài)代理注意,代理類是真實類實現(xiàn)共同的接口,并且代理類引用真實類對象,將耗時操作放在代理類方法中實現(xiàn)。
動態(tài)代理:
動態(tài)代理即運行時,動態(tài)生成代理類。即:代理類的字節(jié)碼在運行時生成并載入當前的classloader。與靜態(tài)代理相比,動態(tài)代理不需要為真實注意封裝一個形式上完全一樣的封裝類,假如主題接口很多,就要為每一個接口寫一個代理方法是很煩人的,如果接口有變動,真實類和代理類都需要變化,這樣不利于系統(tǒng)維護;其次,使用一些動態(tài)代理的生成方法甚至可以在運行是指定代理類的執(zhí)行邏輯,從而大大提高的系統(tǒng)的靈活性。
主題接口:
public interface IDBQuery { String request(); }
jdk代理類:
public class JdbDbqueryHandler implements InvocationHandler{ IDBQuery idbquery = null; @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(idbquery==null){ idbquery = new DBQuery(); } return idbquery.request(); } public static IDBQuery createJdbProxy(){ IDBQuery jdkProxy = (IDBQuery) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{IDBQuery.class}, new JdbDbqueryHandler()); System.out.println("JdbDbqueryHandler.createJdbProxy()"); return jdkProxy; } }
主函數(shù):
public class ProxyText { public static void main(String[] args) { IDBQuery idbQuery = JdbDbqueryHandler.createJdbProxy(); System.out.println(idbQuery.request()); } }
另外,也可以使用CGLIB和javassist動態(tài)代理與jdk動態(tài)代理類似,但是jdk動態(tài)類的創(chuàng)建過程最快,因為這個內(nèi)置實現(xiàn)的difineclass()方法被定義為native實現(xiàn),故性能優(yōu)于其他。在代理類的函數(shù)調(diào)用上,JDK的動態(tài)代理不如CGLIB和javassist動態(tài)代理,而javassist動態(tài)代理性能質(zhì)量最差,甚至不如JDK的實現(xiàn)。在實際開發(fā)應用中,代理類的方法調(diào)用頻率要遠遠高于代理類的實際生成頻率,故動態(tài)代理的方法調(diào)用性能應該成為性能的關注點。JDK動態(tài)代理強制要求代理類和真是主題實現(xiàn)統(tǒng)一接口,CGLIB和javassist動態(tài)代理沒有這樣的要求。
在java中,動態(tài)代理的實現(xiàn)涉及到classloader的使用,以CGLIB為例,簡要描述下動態(tài)類的加載過程。使用CGLIB生成動態(tài)代理,首先需要生成Enhancer類的實例,并制定用于處理代理業(yè)務的回調(diào)類。在enhancer.create()方法中,會使用DefaultGeneratorStrategy.Generate()方法生成代理類的字節(jié)碼,并保存在byte數(shù)組中。接著調(diào)用reflectUtils.defineClass()方法,通過反射,調(diào)用ClassLoader.defineClass()方法,將字節(jié)碼裝載到classloader中,完成類的加載。最后,通過reflectUtils.newInstance()方法,通過反射生成動態(tài)類實例,并返回該實例。其他與該過程細節(jié)不同,但是生成邏輯相同。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助。
相關文章
Spring-Bean創(chuàng)建對象的步驟方式詳解
在本篇文章里小編給大家分享的是關于Spring-Bean創(chuàng)建對象的步驟方式詳解內(nèi)容,有興趣的朋友們跟著學習下。2020-02-02Java Servlet簡單實例分享(文件上傳下載demo)
下面小編就為大家?guī)硪黄狫ava Servlet簡單實例分享(文件上傳下載demo)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-05-05詳解java封裝返回結果與RestControllerAdvice注解
這篇文章主要為大家介紹了java封裝返回結果與RestControllerAdvice注解實例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-09-09SpringBoot整合Netty實現(xiàn)WebSocket的示例代碼
本文主要介紹了SpringBoot整合Netty實現(xiàn)WebSocket的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-05-05SpringBoot + minio實現(xiàn)分片上傳、秒傳、續(xù)傳功能
MinIO是一個基于Go實現(xiàn)的高性能、兼容S3協(xié)議的對象存儲,使用MinIO構建用于機器學習,分析和應用程序數(shù)據(jù)工作負載的高性能基礎架構,這篇文章主要介紹了SpringBoot + minio實現(xiàn)分片上傳、秒傳、續(xù)傳,需要的朋友可以參考下2023-06-06