成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Android設(shè)計(jì)模式之從OKHttp的攔截器中學(xué)習(xí)責(zé)任鏈模式

開發(fā) 前端
相信大家在Android開發(fā)過程中都用到過okhttp或是Retrofit網(wǎng)絡(luò)請求框架,而okhttp中就是使用到了責(zé)任鏈設(shè)計(jì)模式,即便使用的時(shí)retrofit,而retrofit也只是封裝的okhttp。

[[417550]]

前言

責(zé)任鏈模式,顧名思義,就是由一個(gè)個(gè)負(fù)有一定責(zé)任的單元形成的一個(gè)鏈條,

在這個(gè)鏈條上,每個(gè)責(zé)任單元都負(fù)責(zé)自己應(yīng)該負(fù)責(zé)的責(zé)任,

而責(zé)任單元之間時(shí)互不干擾的,當(dāng)有事件需要處理時(shí),從鏈條的

首個(gè)責(zé)任單元開始處理,首個(gè)責(zé)任單元處理事件中自己負(fù)責(zé)的部分,

當(dāng)處理完之后,若事件還未處理完

畢,還需進(jìn)一步處理而同時(shí)當(dāng)前責(zé)任單元無法處理或是不是自己負(fù)責(zé)的部分時(shí),

當(dāng)前責(zé)任單元將事件傳

遞給下一個(gè)責(zé)任單元,而后面該哪個(gè)責(zé)任單元處理,當(dāng)前責(zé)任單元不關(guān)心,

當(dāng)前責(zé)任單元只需處理自己

負(fù)責(zé)的部分并確定事件是否該繼續(xù)傳遞到下一責(zé)任單元。

Android開發(fā)中用到的責(zé)任鏈模式

  • 相信大家在Android開發(fā)過程中都用到過okhttp或是Retrofit網(wǎng)絡(luò)請求框架,而okhttp中就是使用到了責(zé)任鏈設(shè)計(jì)模式,即便使用的時(shí)retrofit,而retrofit也只是封裝的okhttp。
  • okhttp中的攔截器使用的就是責(zé)任鏈設(shè)計(jì)模式,相信大家都會有用到過這其中的攔截器去處理網(wǎng)絡(luò)請求,比如對Cookie的處理。下面將從okhttp攔截器的實(shí)現(xiàn)源碼角度學(xué)習(xí)責(zé)任鏈設(shè)計(jì)模式。

攔截器的使用

如需對cookie進(jìn)行處理,我們一般會定義一個(gè)攔截器類繼承自Interceptor,并重寫intercept方法,

在該方法中處理cookie(添加或獲取cookie保存),

以下代碼實(shí)現(xiàn)的是向請求頭加入cookie的攔截器,獲取請求頭中cookie方法與此類似,這里不做展示。

  1. /** 
  2.  * 定義OkHttp3攔截器,處理數(shù)據(jù)包的header,向header種添加cookie 
  3.  */ 
  4. public class InterceptorOfAddCookie implements Interceptor { 
  5.     private static final String TAG = "InterceptorOfAddCookie"
  6.     @Override 
  7.     public Response intercept(Chain chain) throws IOException { 
  8.         Log.d(TAG, "InterceptorOfAddCookie"); 
  9.         return chain.proceed(chain.request()); 
  10.     } 

接著向okhttpClient對象中添加攔截器,使用的方法如下面的addInterceptor方法,參數(shù)就是創(chuàng)建的攔截器類對象,我這里是添加了兩個(gè)攔截器,包括cookie的添加和獲取。

  1. okHttpClient = new OkHttpClient 
  2.         .Builder() 
  3.         .addInterceptor(new InterceptorOfAddCookie()) 
  4.         .addInterceptor(new InterceptorOfReceivedCookie()) 
  5.         .build(); 

正式進(jìn)入正題,切入點(diǎn)就在這里的addInterceptor方法,查看一下該方法的源碼,看一下內(nèi)部實(shí)現(xiàn)了怎樣的邏輯處理。

  1. /** 
  2.  * 通過addInterceptor方法將自定義的cookie處理攔截器添加到這的interceptor 
  3.  * 中,在源碼中可以看到interceptors其實(shí)就是一個(gè)List集合,即攔截器集合,而這里 
  4.  * 的攔截器集合就可以看作是我們這次責(zé)任鏈模式中的責(zé)任鏈,集合中的每一個(gè)攔截器就 
  5.  * 相當(dāng)于之前所說的責(zé)任單元。 
  6.  */ 
  7. public Builder addInterceptor(Interceptor interceptor) { 
  8.   if (interceptor == null) throw new IllegalArgumentException("interceptor == null"); 
  9.   interceptors.add(interceptor); 
  10.   return this; 

然后是在再看到ohhttpClient中使用攔截器并發(fā)送請求的過程

  1. okHttpClient = new OkHttpClient 
  2.         .Builder() 
  3.         .addInterceptor(new InterceptorOfAddCookie()) 
  4.         .addInterceptor(new InterceptorOfReceivedCookie()) 
  5.         .build(); 
  6. Request request = new Request.Builder().url("").get().build(); 
  7. Call call = okHttpClient.newCall(request); 
  8. call.enqueue(new Callback() { 
  9.     @Override 
  10.     public void onFailure(Call call, IOException e) { 
  11.     } 
  12.     @Override 
  13.     public void onResponse(Call call, Response response) throws IOException { 
  14.     } 
  15. }); 

其中攔截器是被添加到了okhttpClient的攔截器集合interceptors中,而通過okHttpClient.newCall(request)方法將okhttpClient引用到了RealCall中的client,

因?yàn)樵趏kHttpClient.newCall()方法源碼如下:

  1. @Override public Call newCall(Request request) { 
  2.   return RealCall.newRealCall(this, request, false /* for web socket */); 

可以看到newCall方法實(shí)際上創(chuàng)建的是RealCall對象,RealCall類實(shí)現(xiàn)了Call方法。接著再到call對象調(diào)用enqueue(CallBack callBack)方法發(fā)起請求,進(jìn)入到enqueue內(nèi)部查看,即進(jìn)入到RealCall中的enqueue()方法中:

  1. @Override public void enqueue(Callback responseCallback) { 
  2.   synchronized (this) { 
  3.     if (executed) throw new IllegalStateException("Already Executed"); 
  4.     executed = true
  5.   } 
  6.   transmitter.callStart(); 
  7.   client.dispatcher().enqueue(new AsyncCall(responseCallback)); 

可以看到這邊創(chuàng)建了一個(gè)AsyncCall對象,并傳入CallBack對象,在RealCall類中可以找到合格內(nèi)部類AsyncCall是繼承自NamedRunnable,而進(jìn)一步查看NamedRunnable是繼承自

Runnable,所以AsyncCall可以被看作為一個(gè)Runnable

沿著client.dispatcher().enqueue(new AsyncCall(responseCallback));方法進(jìn)入到Dispatcher類中的enqueue方法中,

  1. void enqueue(AsyncCall call) { 
  2.   synchronized (this) { 
  3.     readyAsyncCalls.add(call); 
  4.     // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to 
  5.     // the same host. 
  6.     if (!call.get().forWebSocket) { 
  7.       AsyncCall existingCall = findExistingCallWithHost(call.host()); 
  8.       if (existingCall != null) call.reuseCallsPerHostFrom(existingCall); 
  9.     } 
  10.   } 
  11.   promoteAndExecute(); 

可以發(fā)現(xiàn)這里最終調(diào)用了promoterAndExecute()方法,再看一下這個(gè)方法中具體實(shí)現(xiàn)

  1. private boolean promoteAndExecute() { 
  2.   assert (!Thread.holdsLock(this)); 
  3.   List<AsyncCall> executableCalls = new ArrayList<>(); 
  4.   boolean isRunning; 
  5.   synchronized (this) { 
  6.     for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) { 
  7.       AsyncCall asyncCall = i.next(); 
  8.       if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity. 
  9.       if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity. 
  10.       i.remove(); 
  11.       asyncCall.callsPerHost().incrementAndGet(); 
  12.       executableCalls.add(asyncCall); 
  13.       runningAsyncCalls.add(asyncCall); 
  14.     } 
  15.     isRunning = runningCallsCount() > 0; 
  16.   } 
  17.   for (int i = 0, size = executableCalls.size(); i < size; i++) { 
  18.     AsyncCall asyncCall = executableCalls.get(i); 
  19.     asyncCall.executeOn(executorService()); 
  20.   } 
  21.   return isRunning; 

可以發(fā)現(xiàn)在這個(gè)方法最終會調(diào)用

  1. asyncCall.executeOn(executorService());這里的executeOn傳入的參為線程池對象 
  2. ExecutorService實(shí)例,在回到AsyncCall類中查看executeOn方法的具體實(shí)現(xiàn), 
  3. void executeOn(ExecutorService executorService) { 
  4.   assert (!Thread.holdsLock(client.dispatcher())); 
  5.   boolean success = false
  6.   try { 
  7.     executorService.execute(this); 
  8.     success = true
  9.   } catch (RejectedExecutionException e) { 
  10.     InterruptedIOException ioException = new InterruptedIOException("executor rejected"); 
  11.     ioException.initCause(e); 
  12.     transmitter.noMoreExchanges(ioException); 
  13.     responseCallback.onFailure(RealCall.this, ioException); 
  14.   } finally { 
  15.     if (!success) { 
  16.       client.dispatcher().finished(this); // This call is no longer running! 
  17.     } 
  18.   } 

可以看到executorService.execute(this);就是將this(即AsyCall對象,而AsyncCall之前提到它的父類NameRunnable是實(shí)現(xiàn)了Runnable的)傳入到線程池中,當(dāng)線程池執(zhí)行該Runnable任務(wù)時(shí)回執(zhí)行run()方法,而可以看到AsyncCall父類NameRunnable類中的run()方法是調(diào)用了自身的execute()方法,而在AsyncCall中重寫了該execute()方法,即執(zhí)行NameRunnable的execute()相當(dāng)于執(zhí)行了AsyncCall類中的execute()方法。

再看到execute()方法中,在這個(gè)方法中主要看到Response response = getResponseWithInterceptorChain();這一行,查看一下getResponseWithInterceptorChain()方法的實(shí)現(xiàn):

  1. Response getResponseWithInterceptorChain() throws IOException { 
  2.   // Build a full stack of interceptors. 
  3.   List<Interceptor> interceptors = new ArrayList<>(); 
  4.   interceptors.addAll(client.interceptors()); 
  5.   interceptors.add(new RetryAndFollowUpInterceptor(client)); 
  6.   interceptors.add(new BridgeInterceptor(client.cookieJar())); 
  7.   interceptors.add(new CacheInterceptor(client.internalCache())); 
  8.   interceptors.add(new ConnectInterceptor(client)); 
  9.   if (!forWebSocket) { 
  10.     interceptors.addAll(client.networkInterceptors()); 
  11.   } 
  12.   interceptors.add(new CallServerInterceptor(forWebSocket)); 
  13.   Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0, 
  14.       originalRequest, this, client.connectTimeoutMillis(), 
  15.       client.readTimeoutMillis(), client.writeTimeoutMillis()); 
  16.   boolean calledNoMoreExchanges = false
  17.   try { 
  18.     Response response = chain.proceed(originalRequest); 
  19.     if (transmitter.isCanceled()) { 
  20.       closeQuietly(response); 
  21.       throw new IOException("Canceled"); 
  22.     } 
  23.     return response; 
  24.   } catch (IOException e) { 
  25.     calledNoMoreExchanges = true
  26.     throw transmitter.noMoreExchanges(e); 
  27.   } finally { 
  28.     if (!calledNoMoreExchanges) { 
  29.       transmitter.noMoreExchanges(null); 
  30.     } 
  31.   } 

這里發(fā)現(xiàn)了創(chuàng)建了一個(gè)攔截器集合,并通過client.interceptors()方法獲取到了client的攔截器集合interceptors,隨后也往新創(chuàng)建的攔截器集合添加了其他的攔截器,而client中的攔截器集合包含的只是我們自定義的攔截器集合,還記得起初提到的創(chuàng)建okhttpClient實(shí)例時(shí)通過addInterceptor方法添加自定義攔截器嗎?所以在這里也可以發(fā)現(xiàn),如果處理攔截器的時(shí)候會先執(zhí)行我們自定義的攔截器再執(zhí)行內(nèi)部的攔截器。

再往下看會發(fā)現(xiàn)Interceptor.Chain chain = new RealInterceptorChain()傳入iterceptors創(chuàng)建了Interceptor.Chain,這個(gè)就是責(zé)任鏈,將攔截器集合都放到這個(gè)鏈條上,組成了一個(gè)攔截器責(zé)任鏈。

注意:RealInterceptorChain實(shí)現(xiàn)了Interceptor接口中的內(nèi)部接口Chain接口。

接著往下看Response response = chain.proceed(originalRequest);這里執(zhí)行了chain的proceed方法并傳入了Request對象originalRequest(即是我們最初創(chuàng)建

Call call = okHttpClient.newCall(request),RealCall對象)

接著再看chain.proceed方法的具體實(shí)現(xiàn)(進(jìn)入到RealInterceptorChain類中,因?yàn)樵擃悓?shí)現(xiàn)了Chain接口,所以具體邏輯實(shí)現(xiàn)會在該類的proceed中):

  1. @Override public Response proceed(Request request) throws IOException { 
  2.   return proceed(request, transmitter, exchange); 

其內(nèi)部依然調(diào)用proceed方法,再看自身的proceed方法:

  1. public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange) 
  2.     throws IOException { 
  3.   if (index >= interceptors.size()) throw new AssertionError(); 
  4.   calls++; 
  5.   // If we already have a stream, confirm that the incoming request will use it. 
  6.   if (this.exchange != null && !this.exchange.connection().supportsUrl(request.url())) { 
  7.     throw new IllegalStateException("network interceptor " + interceptors.get(index - 1) 
  8.         + " must retain the same host and port"); 
  9.   } 
  10.   // If we already have a stream, confirm that this is the only call to chain.proceed(). 
  11.   if (this.exchange != null && calls > 1) { 
  12.     throw new IllegalStateException("network interceptor " + interceptors.get(index - 1) 
  13.         + " must call proceed() exactly once"); 
  14.   } 
  15.   // Call the next interceptor in the chain. 
  16.   RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange, 
  17.       index + 1, request, call, connectTimeout, readTimeout, writeTimeout); 
  18.   Interceptor interceptor = interceptors.get(index); 
  19.   Response response = interceptor.intercept(next); 
  20.   // Confirm that the next interceptor made its required call to chain.proceed(). 
  21.   if (exchange != null && index + 1 < interceptors.size() && next.calls != 1) { 
  22.     throw new IllegalStateException("network interceptor " + interceptor 
  23.         + " must call proceed() exactly once"); 
  24.   } 
  25.   // Confirm that the intercepted response isn't null
  26.   if (response == null) { 
  27.     throw new NullPointerException("interceptor " + interceptor + " returned null"); 
  28.   } 
  29.   if (response.body() == null) { 
  30.     throw new IllegalStateException( 
  31.         "interceptor " + interceptor + " returned a response with no body"); 
  32.   } 
  33.   return response; 
  34. //其中最關(guān)鍵的代碼在于這三行代碼 
  35. RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,index + 1, request, call, connectTimeout, readTimeout, writeTimeout); 
  36. Interceptor interceptor = interceptors.get(index); 
  37. Response response = interceptor.intercept(next); 

這里又通過調(diào)用RealInterceptorChain類構(gòu)造方法,而這里不同的是,參數(shù)index的值為index+1,并且在該類中index為全局變量,所以index的值增量為1,通過index將攔截器集合interceptors中的第index個(gè)攔截器interceptor取出,并執(zhí)行interceptor的interceprt(Chain)方法,接著我們回顧一下最初我們自定義的攔截其中實(shí)現(xiàn)了什么邏輯:

  1. public class InterceptorOfAddCookie implements Interceptor { 
  2.     private static final String TAG = "InterceptorOfAddCookie"
  3.     @Override 
  4.     public Response intercept(Chain chain) throws IOException { 
  5.         Log.d(TAG, "InterceptorOfAddCookie"); 
  6.         return chain.proceed(chain.request()); 
  7.     } 

可以看到intercept(Chain)(這里的Chain為RealInterceptorChain)方法中調(diào)用了

chain.proceed(Request)方法,即又調(diào)用了proceed方法,而前面分析到RealInterceptorChain重寫父接口的proceed方法的具體實(shí)現(xiàn)中又調(diào)用了RealInterceptorChain自身的proceed方法,而自身的proceed方法又調(diào)用了interceptor.intercept()方法,所以這里是形成了一個(gè)遞歸,而這里的遞歸

思想就是責(zé)任鏈模式的核心思想。即不斷執(zhí)行攔截器interceptor中的intercept(Chain)方法,而我們只需要在intercept方法中實(shí)現(xiàn)我們的邏輯即可,可以通過Chain獲取到Request或者Response,實(shí)現(xiàn)對請求體或請求頭的處理,如處理請求頭的cookie。

總結(jié)

okhttp中的攔截器實(shí)現(xiàn)可以總結(jié)為如下:

這樣的設(shè)計(jì)方法明顯易于后續(xù)擴(kuò)展,

而不會涉及到期待責(zé)任單元的邏輯更改,

只需創(chuàng)建一個(gè)類要實(shí)現(xiàn)責(zé)任單元接口,創(chuàng)建這個(gè)類的實(shí)例,

并將其添加到責(zé)任鏈中即可。該設(shè)計(jì)模式的關(guān)鍵思想在于遞歸,

在責(zé)任鏈Chain中通過遞歸調(diào)用責(zé)任單元方法,

即可將要處理的事件沿著責(zé)任鏈傳遞處理,

也可以在責(zé)任單元中通過邏輯判斷是否要將事件繼續(xù)傳遞到下一責(zé)任單元。

本文轉(zhuǎn)載自微信公眾號「Android開發(fā)編程 」

 

責(zé)任編輯:姜華 來源: Android開發(fā)編程
相關(guān)推薦

2021-12-24 07:50:45

責(zé)任鏈模式設(shè)計(jì)

2010-04-01 09:10:03

PHP設(shè)計(jì)模式責(zé)任鏈模式

2012-03-28 13:28:56

Java設(shè)計(jì)模式

2023-06-05 07:55:31

2021-03-10 08:20:54

設(shè)計(jì)模式OkHttp

2024-01-30 13:15:00

設(shè)計(jì)模式責(zé)任鏈

2023-09-26 00:27:07

設(shè)計(jì)模式鏈接

2020-11-17 09:32:57

設(shè)計(jì)模式責(zé)任鏈

2023-05-18 08:54:22

OkHttp源碼解析

2022-12-28 08:08:57

2024-05-09 12:17:00

責(zé)任鏈設(shè)計(jì)模式

2022-11-01 08:46:20

責(zé)任鏈模式對象

2023-09-04 13:14:00

裝飾器設(shè)計(jì)模式

2023-09-28 08:45:56

開源責(zé)任鏈模式

2024-06-04 13:11:52

Python行為設(shè)計(jì)模式開發(fā)

2021-06-22 15:27:13

設(shè)計(jì)模式迭代器模式Java

2023-12-13 13:28:16

裝飾器模式Python設(shè)計(jì)模式

2024-12-03 15:52:45

責(zé)任鏈Java

2021-04-19 21:25:48

設(shè)計(jì)模式到元

2021-07-14 10:08:30

責(zé)任鏈模式加工鏈
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 国产精品三级久久久久久电影 | 国产精品一区2区 | 国产精品1 | 国产一级电影网 | 久草在线 | 在线国产一区二区 | 五月天婷婷久久 | 精品视频一区二区三区在线观看 | 国产精品久久二区 | 久久久片 | 日韩欧美一区二区三区四区 | 亚洲福利一区二区 | 黄色高清视频 | 中文二区 | 国内精品久久精品 | 精品久久久久久 | 欧洲性生活视频 | 欧美精品一区二区三区蜜桃视频 | 中文字幕日本一区二区 | 国产高清在线 | 国产精品久久久久久福利一牛影视 | av影音| 精品欧美乱码久久久久久1区2区 | 国产不卡在线观看 | 成人国产精品久久久 | 欧美一区二区大片 | 欧美色性 | 成人精品在线观看 | 国产性网 | 国产精品成人一区二区 | 日韩中文字幕 | 亚洲视频在线观看 | 成人黄色av| 亚洲一区二区三区视频在线 | 成人国产一区二区三区精品麻豆 | 日本不卡一区二区三区在线观看 | 日本久久久久久 | 欧美一区永久视频免费观看 | 午夜免费电影 | 国产视频久久久 | 91精品国产综合久久精品 |