当前位置: 首页 > 科技观察

Android设计模式之从OKHttp的拦截器中学习责任链模式

时间:2023-03-19 16:24:39 科技观察

Android设计模式:从OKHttpInterceptor学习责任链模式自己应该负责的责任,责任单位之间互不干扰。当有事件需要处理时,从链上的第一个责任单元开始处理。第一责任单位处理事件中你负责的部分。处理后,如果事件还没有处理,需要进一步处理,而当前责任单位无法处理或不属于自己的责任,则当前责任单位将事件传递给下一个责任单位,哪个责任单位应该稍后处理,当前责任单位不关心,当前责任单位只需要处理它负责的部分,并判断该事件是否应该继续传递给下一个责任单位。Android开发中使用的责任链模型相信大家都在Android开发过程中使用过okhttp或者Retrofit网络请求框架,而okhttp使用的是责任链设计模型,即使使用retrofit,retrofit也只是对okhttp的封装。okhttp中的拦截器采用责任链设计模式。相信大家都用过这个拦截器来处理网络请求,比如处理cookie。下面将从okhttp拦截器的实现源码的角度来学习责任链设计模式。拦截器的使用处理cookie,我们一般会定义一个拦截器类,继承自Interceptor,并重写拦截方法,在拦截方法中处理cookie(添加或获取cookie存储),下面的代码实现在请求中添加cookie拦截器header,获取请求头中cookie的方法与此类似,这里不再赘述。/***定义OkHttp3拦截器,处理数据包包头,在包头中添加cookies*/publicclassInterceptorOfAddCookieimplementsInterceptor{privatestaticfinalStringTAG="InterceptorOfAddCookie";@OverridepublicResponseintercept(Chainchain)throwsIOException{Log.d(TAG,"InterceptorOfAddCookie");returnchainproceed(chain.request());}}然后给okhttpClient对象添加一个拦截器,使用的方法是下面的addInterceptor方法,参数是创建的拦截器类对象,这里我添加了两个拦截器,包括cookies的添加和获得。okHttpClient=newOkHttpClient.Builder().addInterceptor(newInterceptorOfAddCookie()).addInterceptor(newInterceptorOfReceivedCookie()).build();正式进入正题,这里的切入点是addInterceptor方法,查看这个方法的源码,看看内部实现了什么样的逻辑处理。/***通过addInterceptor方法将自定义的cookie处理拦截器添加到这个拦截器*中。在源码中可以看到拦截器其实是一个List集合,也就是拦截器集合,这里的拦截器集合*可以认为是我们责任链模型中的责任链,每个拦截器在集合相当于前面说的责任单位。*/publicBuilderaddInterceptor(Interceptorinterceptor){if(interceptor==null)thrownewIllegalArgumentException("interceptor==null");interceptors.add(interceptor);returnthis;}然后看在ohhttpClient中使用拦截器发送请求okHttpClient的过程=newOkHttpClient.Builder().addInterceptor(newInterceptorOfAddCookie()).addInterceptor(newInterceptorOfReceivedCookie()).build();Requestrequest=newRequest.Builder().url("").get().build();Callcall=okHttpClient.newCall(请求);call.enqueue(newCallback(){@OverridepublicvoidonFailure(Callcall,IOExceptione){}@OverridepublicvoidonResponse(Callcall,Responseresponse)throwsIOException{}});其中拦截器添加到okhttpClient的拦截器集合interceptors中,在okHttpClient.newCall(request)方法中,okhttpClient引用了RealCall中的client,因为okHttpClient.newCall()方法源码如下:@OverridepublicCallnewCall(Requestrequest){returnRealCall.newRealCall(this,request,false/*forwebsocket*/);}可以看到newCall方法实际上创建了一个RealCall对象,RealCall类实现了Call方法。然后到call对象调用enqueue(CallBackcallBack)方法发起请求,进入enqueue内部视图,即进入RealCall中的enqueue()方法:@Overridepublicvoidenqueue(CallbackresponseCallback){synchronized(this){if(executed)thrownewIllegalStateException("AlreadyExecuted");executed=true;}transmitter.callStart();client.dispatcher().enqueue(newAsyncCall(responseCallback));}可以看到这里创建了一个AsyncCall对象,CallBackobject传入,在RealCall类中,可以发现符合条件的内部类AsyncCall是继承自NamedRunnable,进一步检查NamedRunnable是继承自Runnable,所以AsyncCall可以看做是一个Runnable,顺着client.dispatcher().enqueue(新异步调用(responseCallback));方法进入Dispatcher类中的enqueue方法中,voidenqueue(AsyncCallcall){synchronized(this){readyAsyncCalls.add(call);//MutatetheAsyncCallsothatitsharestheAtomicIntegerofanexistingrunningcallto//thesamehost.if(!call.get().forWebSocket){AsyncCallexistingCall=findExisting(callhost());if(existingCall!=null)call.reuseCallsPerHostFrom(existingCall);}}promoteAndExecute();}可以发现这里终于调用了promoterAndExecute()方法,再看具体实现此方法中的privatebooleanpromoteAndExecute(){assert(!Thread.holdsLock(this));ListexecutableCalls=newArrayList<>();booleanisRunning;synchronized(this){for(Iteratori=readyAsyncCalls.iterator();i.hasNext();){AsyncCallasyncCall=i.next();if(runningAsyncCalls.size()>=maxRequests)break;//Maxcapacity.if(asyncCall.callsPerHost().get()>=maxRequestsPerHost)continue;//Hostmaxcapacity.i.remove();asyncCall.callsPerHost().incrementAndGet();executableCalls.add(asyncCall);runningAsyncCalls.add(asyncCall);}isRunning=runningCallsCount()>0;}for(inti=0,size=executableCalls.size();i();interceptors.addAll(client.interceptors());interceptors.add(newRetryAndFollowUpInterceptor(client));interceptors.add(newBridgeInterceptor(client.cookieJar()));interceptors.add(newCacheInterceptor(client.internalCache)()));interceptors.add(newConnectInterceptor(client));if(!forWebSocket){interceptors.addAll(client.networkInterceptors());}interceptors.add(newCallServerInterceptor(forWebSocket));Interceptor.Chainchain=newRealInterceptorChain(拦截器,transmitter,null,0,originalRequest,this,client.connectTimeoutMillis(),client.readTimeoutMillis(),client.writeTimeoutMillis();booleancalledNoMoreExchanges=false;try{Responseresponse=chain.proceed(originalRequest);if(transmitter.isCanceled()){closeQuietly(response);thrownewIOException("Canceled");}returnresponse;}catch(IOExceptione){calledNoMoreExchanges=true;throwtransmitter.noMoreExchanges(e);}finally{if(!calledNoMoreExchanges){transmitter.noMoreExchanges(null);}}}发现已经创建了拦截器集合,通过client.interceptors()方法获取客户端拦截器集合interceptors,然后在新创建的拦截器集合中添加其他拦截器。客户端中的拦截器集合只包含我们自定义的拦截器集合。还记得开头提到的创建okhttpClient实例时通过addInterceptor方法添加自定义拦截器吗?所以这里也可以发现,如果处理拦截器有时候我们会先执行我们自定义的拦截器,然后再执行内部拦截器,再往下看,会发现Interceptor.Chainchain=newRealInterceptorChain()被传递给iterceptors创建Interceptor.Chain。这就是责任链,拦截器的集合就是放到这个链上就构成了拦截器责任链。注:RealInterceptorChain在Interceptor接口中实现了内部接口Chain接口。然后再往下看Responseresponse=chain.proceed(originalRequest);这里执行了chain的proceed方法,传入了Request对象originalRequest(也就是我们原来创建的Callcall=okHttpClient.newCall(request),RealCall对象)然后看chain.proceed方法的具体实现(进入RealInterceptorChain类,因为这个类实现了Chain接口,所以具体的逻辑实现会在这个类的proceed中):@OverridepublicResponseproceed(Requestrequest)throwsIOException{returnproceed(request,transmitter,exchange);}还是调用proceed方法内部,再看自己的proceed方法:publicResponseproceed(Requestrequest,Transmittertransmitter,@NullableExchangeexchange)throwsIOException{if(index>=interceptors.size())thrownewAssertionError();calls++;//如果我们已经有一个stream,confirmthattheincomingrequestwilluseitif(this.exchange!=null&&!this.exchange.connection().supportsUrl(request.url())){thrownewIllegalStateException("networkinterceptor"+interceptors.get(index-1)+"mustretainthesamehostandport");}//如果我们已经有流,确认这是唯一的链调用。proceed().if(this.exchange!=null&&calls>1){thrownewIllegalStateException("networkinterceptor"+interceptors.get(index-1)+"mustcallproceed()exactlyonce");}//Callthenextinterceptorinthechain.RealInterceptorChainnext=newRealInterceptorChain(interceptors,transmitter,exchange,index+1,request,call,connectTimeout,readTimeout,writeTimeout);Interceptorinterceptor=interceptors.get(index);Responseresponse=interceptor.intercept(next);//确认下一个拦截器需要calltochain.proceed().if(exchange!=null&&index+1