相信我們?cè)诰W(wǎng)上和平時(shí)學(xué)習(xí)和工作中或多或少都接觸過Java的代理模式,經(jīng)常聽到什么靜態(tài)代理、動(dòng)態(tài)代理的一些名詞 。但我們是否真的很清楚這些呢?至少我在面試時(shí),發(fā)現(xiàn)很多人并不很清楚 。首先代理比較好理解,就是幫一個(gè)人,或者一類人做一些事情 。遷移到面向?qū)ο蟮某绦蛟O(shè)計(jì)中,代理就是幫一個(gè)類去做一些事情,而這個(gè)代理的工具我們就稱為代理類 。通過代理的方式去做事有什么好處呢?這就好比工廠和分銷商做的事情一樣,工廠可以直賣一些自己的產(chǎn)品,分銷商同樣也可以賣工廠生產(chǎn)的產(chǎn)品,那么為什么還有分銷商的存在呢?因?yàn)榉咒N商可以供一些額外的服務(wù),或者在銷售的過程中能夠完成一些其他的事情,比如組合銷售、根據(jù)本地情況做活動(dòng)等,而這些可能是工廠不想關(guān)心或者也管不過來的 。這樣的功能和角色承包給代理商就會(huì)使得分工比較明晰,并且又能夠供一些額外或者定制的服務(wù) 。靜態(tài)代理Java中的代理方式可以分為靜態(tài)代理和動(dòng)態(tài)代理 。靜態(tài)代理的含義是代理類/對(duì)象在我們關(guān)心的程序運(yùn)行前就已經(jīng)確定或存在 。靜態(tài)代理比較好理解,我們?cè)谌粘9ぷ髦幸彩墙?jīng)常用到,比如一個(gè)已經(jīng)存在的接口,我們不期望去更改它,但是現(xiàn)在要在原邏輯上新加一些邏輯或功能,比如原接口方法調(diào)用完成后發(fā)送一個(gè)消息之類的 。于是我們可以創(chuàng)建一個(gè)類,同樣實(shí)現(xiàn)原接口,并且把之前存在的接口當(dāng)做成員變量注入進(jìn)來,調(diào)用其中的方法,并添加我們需要的功能 。靜態(tài)代理的類圖如下所示,需要被代理的實(shí)現(xiàn)類和代理類都實(shí)現(xiàn)了抽象接口AbstractInterface,而InterfaceProxy和InterfaceImpl間是聚合關(guān)系 。

文章插圖
來看一段示例代碼,ProductAuditCallbackService 是我們已有的一個(gè)接口,出于某些原因,這個(gè)接口不能繼續(xù)對(duì)外使用,我們需要定義一個(gè)新的接口并且名稱還要一樣(主要是方便客戶理解和對(duì)應(yīng)原接口),但是我們需要添加一點(diǎn)“新邏輯” 。因此我們可以同樣實(shí)現(xiàn) ProductAuditCallbackService,ProductAuditCallbackServiceProxy 就是我們的代理類,之后外部調(diào)用就可以實(shí)例化我們的代理類,調(diào)用同名方法就好了 。1 public class ProductAuditCallbackServiceProxy implements ProductAuditCallbackService { 2 3 @Resource 4 private ProductAuditCallbackService productAuditCallbackService; 5 6 @Override 7 public Result auditProduct(ProductAuditRequest request, String auditStatus) { 8 if (auditStatus == "DELETED") { 9 return new Result<>;10 }11 return productAuditCallbackService.auditProduct(request, auditStatus);12 }13 14 15 ...16 } 動(dòng)態(tài)代理動(dòng)態(tài)代理的作用和靜態(tài)代理一樣,主要的區(qū)別就在于需要在運(yùn)行時(shí)生成代理類 。在使用動(dòng)態(tài)代理時(shí),我們還需要定義一個(gè)在代理類和委托類之間的中介類,并且中介類需要實(shí)現(xiàn) java.lang.reflect.InvocationHandler 接口 。1 package java.lang.reflect; 2 3 /** 4 * {@code InvocationHandler} is the interface implemented by 5 * the invocation handler of a proxy instance. 6 * 7 *Each proxy instance has an associated invocation handler. 8 * When a method is invoked on a proxy instance, the method 9 * invocation is encoded and dispatched to the {@code invoke}10 * method of its invocation handler.11 *12 * @author Peter Jones13 * @see Proxy14 * @since 1.315 */16 public interface InvocationHandler {17 18 public Object invoke(Object proxy, Method method, Object[] args)19 throws Throwable;20 }動(dòng)態(tài)代理在框架類的代碼中用到的頻率并不低,而且能夠使我們的代碼看起來更高級(jí)一些,所以何樂而不為呢? 讓我們來看一些實(shí)際的例子 。MethodInvocationHandler是一個(gè)中介類,實(shí)現(xiàn)了InvocationHandler接口,MethodMonitor 這個(gè)類的功能就是要統(tǒng)計(jì)我們的委托類的對(duì)象business中的方法被調(diào)用的次數(shù)和耗時(shí),由于其主要功能不是我們關(guān)注的主要內(nèi)容,所以忽略其實(shí)現(xiàn) 。1 public class MethodInvocationHandler implements InvocationHandler { 2 3 //被代理對(duì)象 4 private Object business; 5 6 private final MethodMonitor methodMonitor; 7 8 public MethodInvocationHandler(MethodMonitor methodMonitor) { 9 this.methodMonitor = methodMonitor;10 }11 12 /**13 * 代理方法14 */15 @Override16 public Object invoke(Object proxy, Method method, Object[] args)17 throws Throwable {18 19 long startTime = System.currentTimeMillis;20 21 Object result = method.invoke(this.business, args);22 23 //方法調(diào)用統(tǒng)計(jì)24 this.methodMonitor.methodCount(this.business.getClass.getSimpleName + POINT + method.getName, startTime);25 return result;26 }27 28 }其余示例代碼及外部調(diào)用示例如下,我們的Business類里面擁有三個(gè)方法 。MethodSampleClient 則是一個(gè)封裝起來的客戶端 。我們不想讓外部客戶端感知我們的實(shí)現(xiàn)以及和Business的關(guān)系,于是我們?cè)贛ethodSampleClient中定義了一個(gè)成員變量proxy,當(dāng)外部需要Business供的一些功能時(shí),我們通過proxy為其供 。Proxy.newProxyInstance 則是我們實(shí)例化一個(gè)代理類的方式,喲,這還是個(gè)工廠模式,可以閱讀一些這個(gè)方法的說明,需要傳入的三個(gè)參數(shù)依次是:需要被代理的類的ClassLoader,被代理類需要被代理的接口的集合,中介處理類的實(shí)例 。這里Business我寫的是一個(gè)確定的類,其實(shí)真正在實(shí)際開發(fā)工作中,我們往往定義的抽象的接口或抽象類,知道運(yùn)行時(shí)才會(huì)確定到底是哪個(gè)實(shí)現(xiàn)類的實(shí)例,這樣可能更容易理解一些:運(yùn)行時(shí)確定委托類的實(shí)現(xiàn)類,運(yùn)行時(shí)生成代理類,并調(diào)用對(duì)應(yīng)的委托類的方法 。1 public class Business { 2 3 public void createJob { 4 System.out.println("test createJob"); 5 } 6 7 8 public void processJob { 9 System.out.println("test processJob");10 }11 12 public void closeJob {13 System.out.println("test closeJob");14 }15 16 }17 18 19 20 public class MethodSampleClient {21 22 private Business business;23 24 @Getter25 private Object proxy;26 27 private InvocationHandler invocationHandler;28 29 30 public void init {31 this.business = new Business;32 this.invocationHandler = new MethodInvocationHandler(new MethodMonitor);33 this.proxy = bind(this.business, invocationHandler);34 }35 36 /**37 * 綁定對(duì)象, 直接初始化并返回代理類供客戶端使用38 */39 public Object bind(Object business, InvocationHandler invocationHandler) {40 return Proxy.newProxyInstance(41 //被代理類的ClassLoader42 business.getClass.getClassLoader,43 //要被代理的接口,本方法返回對(duì)象會(huì)自動(dòng)聲稱實(shí)現(xiàn)了這些接口44 business.getClass.getInterfaces,45 //代理處理器對(duì)象46 invocationHandler);47 }48 49 } 50 51 52 /**53 * A simple client test class54 */55 public class Test {56 57 public void main(String[] args) {58 MethodSampleClient methodSampleClient = new MethodSampleClient;59 methodSampleClient.init;60 61 methodSampleClient.getProxy.createJob;62 methodSampleClient.getProxy.processJob;63 methodSampleClient.getProxy.closeJob;64 }65 66 }為了說清楚這個(gè)過程,竟然還真的寫了不少代碼,看起來比較繁瑣 。總結(jié)一下,動(dòng)態(tài)代理無非按照下面的步驟來編寫代碼:
以上關(guān)于本文的內(nèi)容,僅作參考!溫馨提示:如遇健康、疾病相關(guān)的問題,請(qǐng)您及時(shí)就醫(yī)或請(qǐng)專業(yè)人士給予相關(guān)指導(dǎo)!
「愛刨根生活網(wǎng)」www.malaban59.cn小編還為您精選了以下內(nèi)容,希望對(duì)您有所幫助:- 軟件開發(fā)培訓(xùn)學(xué)校:ASP.NET Core MVC+Layui使用EF Core連接MySQL執(zhí)行簡(jiǎn)單的CRUD操作
- 軟件開發(fā)培訓(xùn)學(xué)校:解Bug之路-記一次存儲(chǔ)故障的排查過程
- 軟件開發(fā)培訓(xùn)學(xué)校:5個(gè)讓人窒息的爛代碼,你看完都忍不了
- 軟件開發(fā)培訓(xùn)學(xué)校:怎么選擇專業(yè)正規(guī)的Unity3d游戲開發(fā)培訓(xùn)學(xué)校?
- 軟件開發(fā)培訓(xùn)學(xué)校:計(jì)算機(jī)培訓(xùn)學(xué)校主要學(xué)什么?
- 軟件開發(fā)培訓(xùn)學(xué)校:IT行業(yè)和程序員一樣嗎?
- 軟件開發(fā)培訓(xùn)學(xué)校:女程序員平均月薪1.5萬(wàn),學(xué)習(xí)投資是男程序員的1.5倍
- 軟件開發(fā)培訓(xùn)學(xué)校:各個(gè)大廠的 404 頁(yè)面!后一個(gè)笑shi我了...
- 軟件開發(fā)培訓(xùn)學(xué)校:牛逼至極!用這個(gè)神器看代碼太舒服了
- 軟件開發(fā)培訓(xùn)學(xué)校:網(wǎng)校系統(tǒng)可以幫助教育企業(yè)解決哪些問題?
