OkHttp攔截器袖珍重寫版
本篇文章建立在看過一遍OkHttp原始碼中的攔截器部分的基礎上。
OkHttp回顧
OkHttp的攔截器工作原理如下圖,每一個攔截器都有機會處理上一個攔截器傳下來的Request或者下一個攔截器返回上來的Response,即可任意地進行前處理和後處理。在最後一個攔截器CallServerInterceptor中進行真正的網路連結,成功後構造Response物件併發布,一層一層地傳遞到開發者手上。


仿寫攔截器
在實戰開發中,僅就涉及資料處理這一方面,攔截器就有非常好的設計效果,OkHttp這一套是可以照搬到很多地方的,攔截器這一套設計實戰性非常高,故在這裡動手擼一個簡易版。
1. 定義Request和Response
/** * 作為責任鏈上一直被傳遞的物件,從構造開始,一直傳遞到最後一個攔截器並被依次捕獲和處理 */ public class Request { public int i = 0; public int j = 1; } /** * 在最後一個攔截器中發生構造,並被依次返回到責任鏈的遞迴,並最終返回給應用層讀取。 */ public class Response { public String param1; public String param2; }
-
請求和響應是最先定義的,實際上這叫做輸入和輸出,Input和Output,只是剛好在網路請求這裡叫做Request和Response,我按照OkHttp的來,也這樣寫了。
-
Request和Response要按照實際業務的需求來定義就行,只要記住一個是責任鏈的輸入,一個是責任鏈的輸出。
2.定義攔截器和責任連結口
public interface Interceptor { //攔截 Response intercept(Chain chain); interface Chain { //獲取請求 Request request(); //處理請求,該方法由拿到了Chain物件引用的攔截器來呼叫。 Response proceed(Request request); } }
3. 實現責任連結口的封裝
/** * 實際上只是對以下3個變數的一個封裝。 */ public class RealInterceptorChain implements Interceptor.Chain { //自始至終被傳遞的請求 private Request mRequest; //攔截器容器 private List<Interceptor> mInterceptors; //攔截器容器的下標。 private int mIndex; public RealInterceptorChain(List<Interceptor> interceptors, int index, Request request) { mRequest = request; mInterceptors = interceptors; mIndex = index; } @Override public Request request() { return mRequest; } @Override public Response proceed(Request request) { //該index處不再有攔截器,異常 if (mIndex >= mInterceptors.size()) throw new AssertionError(); //構造責任鏈,將下標+1,其餘不變。 RealInterceptorChain next = new RealInterceptorChain(mInterceptors, mIndex + 1, mRequest); //獲取當前下標的攔截器 Interceptor interceptor = mInterceptors.get(mIndex); //將變數交給攔截器處理,由攔截器自己轉發給下一個攔截器 return interceptor.intercept(next); } }
4. 完成
一共2個介面,3個類。
攔截器的責任鏈模式就這麼簡單。
後面的封裝就是錦上添花的東西了,比如再寫幾個具體的攔截器,把整個攔截器的功能隱藏起來,只暴露少數的介面給外部等等。總之也是按照OkHttp原始碼那一套寫就不會錯。
使用
這是在沒有任何封裝的條件下的直接new出兩個攔截器例項來測試。
- 構造Request
- 構造攔截器容器
- 新增內部的或外部的攔截器
- 構造第一個Chain物件,交給第一個攔截器,發起責任兩從上到下的處理。
- 拿到處理後的Response,開發者進行處理。
實際上這裡面的第2,3,4步在OkHttp裡面都是封裝了的。當然我們自己實現的時候肯定也得封裝。
import interception.Interceptor; import interception.RealInterceptorChain; import interception.Request; import interception.Response; import java.util.ArrayList; import java.util.List; public class Main { public static void main(String[] args) { //1.構造Request //2.構造攔截器容器 //3.新增內部的或外部的攔截器 //4.構造第一個Chain物件,交給第一個攔截器,發起責任兩從上到下的處理。 //5.拿到處理後的Response,開發者進行處理。 //1 Request request = new Request(); //2 List<Interceptor> interceptors = new ArrayList<>(); //3 interceptors.add(chain -> { //修改Request Request r = chain.request(); r.i = 100; r.j = 99; //將request向責任鏈下部傳遞。 return chain.proceed(r); }); interceptors.add(chain -> { Request r = chain.request(); //最後一個Chain物件只有request方法起作用,用來獲取Request,而不會呼叫proceed,在最後一個攔截器中生成Response直接返回而不再遞迴 Response response = new Response(); if (r.i == 100) { response.param1 = String.valueOf(r.i); } if (r.j == 99) { response.param2 = String.valueOf(r.j); } return response; }); //4 RealInterceptorChain chain = new RealInterceptorChain(interceptors, 0, request); Response response = chain.proceed(request); //5 System.out.println(response.param1); System.out.println(response.param2); } } //列印: //100 //99
在這個測試裡面有兩個攔截器,第一個攔截器對Request的兩個引數進行了賦值,一個100一個99,並沒有處理下面返回的Response。第二個攔截器對Request的值進行了檢查,生成了Response物件並賦值返回。過程如下圖:

全文原始碼: ofollow,noindex">https://github.com/HWilliamgo/EasyInterceptorChain/tree/master