摘要:下面我們通過玩英雄聯盟代練的例子來說明下登錄游戲贏下了一局英雄聯盟,獲得了金幣測試結果登錄游戲贏下了一局英雄聯盟,獲得了金幣可以這樣理解,自己寫代理類的方式就是靜態代理。
前言
剛上大學那會,英雄聯盟火的一塌糊涂,當時每天都想著升到30級開啟排位之旅??墒巧?0級需要大把的時間不說,這時候匹配到的人,水平過于參差不齊,問候你全家的事經常發生,那個時候就想要是能有個代練幫我升到30級該多好啊.....下面我們就通過代碼的方式找下代練-..-
什么是代理模式為其他對象提供一種代理以控制對這個對象的訪問uml類圖
代理模式是一個使用率非常高的模式,像spring的aop,struts2的Form元素映射都采用了代理模式。下面我們來看下類圖中三種角色的具體定義:
subject:抽象主題,可以是接口也可以是抽象類,用來進行業務定義。
realsubject:真實主題類,用來實現真正的業務邏輯。
proxy:代理類,也叫委托類。它負責控制對真實主題類訪問的控制,將所有抽象主題定義的方法委托給realsubject類實現,并在這個過程加上預處理和善后工作,已達到增強功能的目的.
靜態代理靜態代理模式其實就是在類設計階段就將代理類考慮在內,而不是和動態代理和cglib代理一樣動態生成代理類。下面我們通過玩英雄聯盟代練的例子來說明下:
public interface IGame { void login(); void playLOL(); }
public class IGamePlayer implements IGame { private String name; public IGamePlayer(String name) { this.name = name; } @Override public void login() { System.out.println(name+"登錄游戲"); } @Override public void playLOL() { System.out.println(name+"贏下了一局英雄聯盟,獲得了100金幣"); } }
public class IGameProxy implements IGame { private IGamePlayer iGamePlayer; public IGameProxy(IGamePlayer iGamePlayer) { this.iGamePlayer = iGamePlayer; } @Override public void login() { iGamePlayer.login(); } @Override public void playLOL() { iGamePlayer.playLOL(); } }
public class Client { public static void main(String[] args) { IGameProxy iGameProxy = new IGameProxy(new IGamePlayer("bin")); iGameProxy.login(); iGameProxy.playLOL(); } } 測試結果: bin登錄游戲 bin贏下了一局英雄聯盟,獲得了100金幣
可以這樣理解,自己寫代理類的方式就是靜態代理。創建代理類和真實主題類,用代理類控制主題類的訪問。游戲代練登錄賬號,打游戲升級,從而節省我的時間。
動態代理動態代理就是在設計和實現階段不需要關心代理誰,而是在運行時期才去指定代理哪個對象。spring的核心之一就是aop,俗稱面向切面編程,其核心就是采用了動態代理機制。
jdk動態代理
保持IGAME接口和業務邏輯類不變。
//通知(這個例子用來統計登錄接口的耗時) interface IAdvice { void execute(); }
//前置通知 public class BeforeAdvice implements IAdvice { @Override public void execute() { System.out.println("執行前時間:"+System.currentTimeMillis()); } }
//后置通知 public class AfterAdvice implements IAdvice { @Override public void execute() { System.out.println("執行后時間:"+System.currentTimeMillis()); } }
public class DynamicProxy{ private Object target; public DynamicProxy(Object target) { this.target = target; } public Object getInstance(ClassLoader classLoader, Class[] interfaces){ return Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //連接點 if (method.getName().startsWith("login")){ new BeforeAdvice().execute(); } Object objec=method.invoke(target,args); if (method.getName().startsWith("login")){ new AfterAdvice().execute(); } return objec; } }); } }
public class Client { public static void main(String[] args) { IGamePlayer gamePlayer = new IGamePlayer("bin"); DynamicProxy dynamicProxy = new DynamicProxy(gamePlayer); IGame proxy= (IGame) dynamicProxy.getInstance(gamePlayer.getClass().getClassLoader(),gamePlayer.getClass().getInterfaces()); proxy.login(); proxy.playLOL(); } } 測試結果: 執行前時間:1513498759281 bin登錄游戲 執行后時間:1513498759282 bin贏下了一局英雄聯盟,獲得了100金幣
在上面的例子中,我引用了一些aop的術語,例如連接點,通知。實現了一個非常簡單的面向切面編程,由項目經驗的可以看下springaop關于事務的配置,就會明白這樣配置的含義了。
jdk動態代理是面向接口的,也就是說代理對象是根據目標對象的所有接口決定的。到底是怎么實現的呢,我們來看下這一段代碼:
public Object getInstance(ClassLoader classLoader, Class[] interfaces){ return Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //連接點 if (method.getName().startsWith("login")){ new BeforeAdvice().execute(); } Object objec=method.invoke(target,args); if (method.getName().startsWith("login")){ new AfterAdvice().execute(); } return objec; } }); }
Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler()):這個方法是重新生成了一個對象,通過類加載器和該類所有的接口生成。當前生成的方法都是空的,具體邏輯都會由InvocationHandler來實現。InvocationHandler我采用了內部類的方式來實現,具體邏輯都是通過invoke來訪問目標對象。其調用流程就是:client-->DynamicProxy-->InvocationHandler-->IGamePlayer .
cglib代理
jdk提供的動態代理是通過接口實現的,那么cglib就是通過生成目標類的子類實現的。假如你的目標類沒有實現接口,又想使用動態代理,那么cglib是你的不二選擇。
Cglib是一個強大的高性能的代碼生成包,它可以在運行期擴展java類與實現java接口.它廣泛的被許多AOP的框架使用,例如Spring AOP和synaop,為他們提供方法的interception(攔截)。Cglib包的底層是通過使用一個小而快的字節碼處理框架ASM來轉換字節碼并生成新的類.不鼓勵直接使用ASM,因為它要求你必須對JVM內部結構包括class文件的格式和指令集都很熟悉.但是有一點需要額外注意,若目標類是final或者目標方法是static和final的,則不會被cglib方法攔截。
使用cglib需要引入cglib包或者spring-core(spring核心功能已經集成cglib)
public class IGamePlayer{ private String name; public IGamePlayer(String name) { this.name = name; } public IGamePlayer() { } public void login() { System.out.println(name+"登錄游戲"); } public void playLOL() { System.out.println(name+"贏下了一局英雄聯盟,獲得了100金幣"); } }
public class DynamicProxy implements MethodInterceptor { private Object target; public DynamicProxy(Object target) { this.target = target; } public Object getProxyInstance(){ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { //模擬事務 System.out.println("事務開始了"); method.invoke(target,objects); System.out.println("事務結束了"); return null; } }
public class Client { public static void main(String[] args) { IGamePlayer iGamePlayer = new IGamePlayer("bin"); DynamicProxy dynamicProxy = new DynamicProxy(iGamePlayer); IGamePlayer proxy = (IGamePlayer) dynamicProxy.getProxyInstance(); proxy.login(); proxy.playLOL(); } } 測試結果: 事務開始了 bin登錄游戲 事務結束了 事務開始了 bin贏下了一局英雄聯盟,獲得了100金幣 事務結束了
如例子,我們定義了一個目標對象類,沒有實現接口,通過cglib的Enhancer工具類指定父類和回調,創建代理類。實現MethodInterceptor,重寫intercept,相當于jdk動態代理的invoke。
總結代理模式分為靜態代理和動態代理。最大的區別就是靜態代理是自己寫代理,而動態代理是通過運行時動態的生成代理類。動態代理是springaop的核心,又分為jdk代理和cglib代理,前者通過接口生成代理后者通過定義父類的子類來生成代理(類不能為final,方法不能為static和final)。
代理模式或許是大家接觸的最多的模式,有了springaop和aspectj這樣優秀的工具,我們拿來定義即可。在學習aop框架的時候,要先弄清一些專業名詞,切面、切入點、通知、織入,理解這些名詞,知道代理模式的原理,學起aop框架就會游刃有余了。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/70835.html
摘要:虛擬代理如果需要創建一個資源消耗較大的對象,先創建一個消耗相對較小的對象來表示,真實對象只在需要時才會被真正創建。虛擬代理通過使用一個小對象來代表一個大對象,可以減少系統資源的消耗,對系統進行優化并提高運行速度。 概念 代理模式(Proxy Pattern) :一種對象結構型模式。給某一個對象提供一個代理,并由代理對象控制對原對象的引用。 UML showImg(https://seg...
摘要:聊完了工廠模式,下面我們來說框架中的另一個核心設計模式代理模式。這里的外賣小哥就相當于是我們的代理。主要分為代理和代理。 聊完了工廠模式,下面我們來說Spring框架中的另一個核心設計模式——代理模式(Proxy Pattern)。 代理模式 大家可以先不用看概念,先舉個吃飯的例子:比如說我們想吃飯,我們可以選擇自己做飯吃、去飯店吃、叫外賣吃。如果我們選擇自己做著吃,我們就需要去買菜、...
摘要:最近在讀設計模式與開發實踐,在這里把文中的各種設計模式寫出來,以便加深記憶,也可以分享給初學者。經紀人可以全權代表明星和客戶談判,最后把談判結果給明星,明星決定簽約與否。這也違反了面向對象設計原則中的單一職責原則。 最近在讀《javascript設計模式與開發實踐》,在這里把文中的各種設計模式寫出來,以便加深記憶,也可以分享給初學者。如果你不了解設計模式,那么強烈推薦你閱讀一下這本書,...
摘要:什么是代理模式代理模式,類似于明星的經紀人,想要拜訪明星,需要先通過經紀人的溝通。不同于裝飾器,那種動態加載一個對象,可以說在代理模式當中,代理是早已既定的。又稱單一功能原則,面向對象五個基本原則之一。 什么是代理模式 代理模式,類似于明星的經紀人,想要拜訪明星,需要先通過經紀人的溝通。而在JS當中,如果想訪問一個類,需要通過另一個類來間接訪問 。不同于裝飾器,那種動態加載一個對象,可...
閱讀 797·2019-08-30 15:54
閱讀 439·2019-08-30 12:51
閱讀 2022·2019-08-29 16:28
閱讀 2842·2019-08-29 16:10
閱讀 2331·2019-08-29 14:21
閱讀 409·2019-08-29 14:09
閱讀 2127·2019-08-23 16:13
閱讀 1236·2019-08-23 13:59