在阅读retrofit源码的过程中主要参考了该博客:http://www.2cto.com/kf/201405/305248.html
在前面的文章中,在使用动态代理invoke方法来调用我们的方法的时候。
无论是哪种请求,最后都是通过invokeRequest方法来执行http的request
/**
* Execute an HTTP request.
*
* @return HTTP response object of specified {@codetype} or {@code null}.
* @throws RetrofitError if any error occurs duringthe HTTP request.
*/
private Object invokeRequest(RequestInterceptorrequestInterceptor, RestMethodInfo methodInfo,
Object[] args) {
String url = null;
try {
methodInfo.init(); // Ensure all relevant methodinformation has been loaded.//标注1
String serverUrl = server.getUrl();//标注2
RequestBuilder requestBuilder = new RequestBuilder(serverUrl, methodInfo,converter);
requestBuilder.setArguments(args);
requestInterceptor.intercept(requestBuilder);
Request request =requestBuilder.build();
url = request.getUrl();
if (!methodInfo.isSynchronous) {
// If we are executing asynchronously thenupdate the current thread with a useful name.
Thread.currentThread().setName(THREAD_PREFIX+ url.substring(serverUrl.length()));
}
if (logLevel.log()) {
// Log the request data.
request = logAndReplaceRequest("HTTP", request);
}
Object profilerObject = null;
if (profiler != null) {
profilerObject =profiler.beforeCall();
}
long start = System.nanoTime();
Response response =clientProvider.get().execute(request);//标注3
long elapsedTime =TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
int statusCode = response.getStatus();//标注4
if (profiler != null) {
RequestInformation requestInfo =getRequestInfo(serverUrl, methodInfo, request);
//noinspectionunchecked
profiler.afterCall(requestInfo,elapsedTime, statusCode, profilerObject);
}
if (logLevel.log()) {
// Log the response data.
response = logAndReplaceResponse(url,response, elapsedTime);
}
Type type = methodInfo.responseObjectType;
if (statusCode >= 200 && statusCode< 300) { // 2XX ==successful request
// Caller requested the raw Response objectdirectly.
if (type.equals(Response.class)) {
if (!methodInfo.isStreaming) {
// Read the entire stream and replace withone backed by a byte[].
response =Utils.readBodyToBytesIfNecessary(response);
}
if (methodInfo.isSynchronous) {
return response;
}
return new ResponseWrapper(response, response);
}
TypedInput body = response.getBody();
if (body == null) {
if (methodInfo.isSynchronous) {
return null;
}
return new ResponseWrapper(response, null);
}
ExceptionCatchingTypedInput wrapped =new ExceptionCatchingTypedInput(body);
try {
Object convert =converter.fromBody(wrapped, type);
if (methodInfo.isSynchronous) {
return convert;
}
return new ResponseWrapper(response, convert);
} catch (ConversionException e) {
// If the underlying input stream threw anexception, propagate that rather than
// indicating that it was a conversionexception.
if (wrapped.threwException()) {
throw wrapped.getThrownException();
}
// The response body was partially read bythe converter. Replace it with null.
response =Utils.replaceResponseBody(response, null);
throw RetrofitError.conversionError(url, response,converter, type, e);
}
}
response =Utils.readBodyToBytesIfNecessary(response);
throw RetrofitError.httpError(url, response,converter, type);
}catch (RetrofitError e) {
throw e; // Pass through our own errors.
}catch (IOException e) {
if (logLevel.log()) {
logException(e, url);
}
throw RetrofitError.networkError(url, e);
}catch (Throwable t) {
if (logLevel.log()) {
logException(t, url);
}
throw RetrofitError.unexpectedError(url, t);
}finally {
if (!methodInfo.isSynchronous) {
Thread.currentThread().setName(IDLE_THREAD_NAME);
}
}
}
}
标注1:调用RestMethodInfo的init方法,该方法参见附录1
标注2:先说RequestInterceptor,作用很明显,当执行请求时拦截请求以做一些特殊处理,比如添加一些额外的请求参数,参见附录2.
标注3:执行请求,执行的过程亲参见附录3。我们以UrlHttpConnction为例。
标注4:接着解析并分发请求结果了,成功请求时返回结果,解析失败调用ErrorHandler给用户一个自定义异常的机会,但最终都是通过异常抛出到invoke()中的,如果是同步调用,直接抛异常,如果是Callback调用,会回调Callback.failure
附录
1.RestMethodInfo的init方法
synchronized void init() {
if (loaded) return;
parseMethodAnnotations();
parseParameters();
loaded = true;
}
只在第一次调用时解析,因为处一次解析后这个对象就被缓存起来了,下次调同一个方法时可以直接使用
ParseMethodAnnotations()方法是解析方法的注解
ParseParameters()方法是解析方法的参数
对于每一个Annotation,也会获取它的Annotation,看它是否是被RestMethod注解的Annotation,如果是,说明是@GET,@POST类型的注解,就调用parsePath解析请求的Url,requestParam(URL中问号后的内容)及Url中需要替换的参数名(Url中大括号括起来的部分)
寻找Headers Annotation解析Header参数
解析RequestType:SIMPLE,MULTIPART,FORM_URL_ENCODED
parseParameters解析请求参数,即参数的Annotation,@PATH、@HEADER、@FIELD等
2. RequestInterceptor
/**Intercept every request before it is executed in order to add additional data.*/
public interface RequestInterceptor {
/** Called for every request. Add data using methods onthe supplied {@linkRequestFacade}. */
void intercept(RequestFacade request);
interface RequestFacade {
/** Add a header to the request. This will not replaceany existing headers. */
void addHeader(String name, String value);
/**
* Add a path parameter replacement. Thisworks exactly like a {@linkretrofit.http.Path
* @Path}-annotated method argument.
*/
void addPathParam(String name, String value);
/**
* Add a path parameter replacement withoutfirst URI encoding. This works exactly like a
* {@link retrofit.http.EncodedPath@EncodedPath}-annotated method argument.
*/
void addEncodedPathParam(String name, Stringvalue);
/** Add an additional query parameter. This will notreplace any existing query parameters. */
void addQueryParam(String name, String value);
/**
* Add an additional query parameterwithout first URI encoding. This will not replace any
* existing query parameters.
*/
void addEncodedQueryParam(String name, Stringvalue);
}
/** A {@link RequestInterceptor} which does no modification ofrequests. */
RequestInterceptor NONE = new RequestInterceptor() {
@Override public void intercept(RequestFacade request) {
// Do nothing.
}
};
}
RequestInterceptor只有一个方法intercept,接收一个RequestFacade参数,RequestFacade是RequestInterceptor内部的一个接口,这个接口的方法就是添加请求参数,Query、Header什么的。大概可以看出RequestInterceptor的作用了,如果RequestFacade表示一个请求相关的数据,RequestInteceptor.intercept的作用就是向这个RequestFacade中添加额外Header,Param等参数。
RequestFacade的一个子类叫RequestBuilder,用来处理Request请求参数,在invokeRequest中会对RequestBuilder调用intercept方法向RequestBuilder添加额外的参数。
有一个叫RequestInterceptorTape的类,同时实现了RequestFacade与RequestInterceptor,它的作用是:
当作为RequestFacade使用时作为参数传给一个RequestInteceptor,这个RequestInterceptor调用它的addHeader等方法时,它把这些调用及参数记录下来
然后作为RequestInterceptor使用时,将之前记录的方法调用及参数重新应用到它的intercept参数RequestFacade中
在RestHandler.invoke中,如果判断方法的调用不是同步调用,就通过下面的两行代码将用户设置的interceptor需要添加的参数记录到RequestInterceptorTape,然后在invokeRequest中再实际执行参数的添加。
// Apply the interceptor synchronously,recording the interception so we can replay it later.
// This way we still defer argumentserialization to the background thread.
final RequestInterceptorTapeinterceptorTape = new RequestInterceptorTape();
requestInterceptor.intercept(interceptorTape);
RequestBuilder.setArguments()解析调用接口时的实际参数。然后通过build()方法生成一个Request对象
3.urlhttpconnection执行请求
/**Retrofit client that uses {@link HttpURLConnection} for communication. */
public class UrlConnectionClient implements Client {
private static final int CHUNK_SIZE = 4096;
public UrlConnectionClient() {
}
@Override public Response execute(Request request) throws IOException {
HttpURLConnection connection = openConnection(request);
prepareRequest(connection, request);
return readResponse(connection);
}
protected HttpURLConnection openConnection(Request request) throws IOException {
HttpURLConnection connection =
(HttpURLConnection) new URL(request.getUrl()).openConnection();
connection.setConnectTimeout(Defaults.CONNECT_TIMEOUT_MILLIS);
connection.setReadTimeout(Defaults.READ_TIMEOUT_MILLIS);
return connection;
}
void prepareRequest(HttpURLConnection connection, Request request) throws IOException {
connection.setRequestMethod(request.getMethod());
connection.setDoInput(true);
for (Header header : request.getHeaders()) {
connection.addRequestProperty(header.getName(),header.getValue());
}
TypedOutput body = request.getBody();
if (body != null) {
connection.setDoOutput(true);
connection.addRequestProperty("Content-Type", body.mimeType());
long length = body.length();
if (length != -1) {
connection.setFixedLengthStreamingMode((int) length);
connection.addRequestProperty("Content-Length", String.valueOf(length));
}else {
connection.setChunkedStreamingMode(CHUNK_SIZE);
}
body.writeTo(connection.getOutputStream());
}
}
Response readResponse(HttpURLConnectionconnection) throws IOException {
int status = connection.getResponseCode();
String reason = connection.getResponseMessage();
if (reason == null) reason = ""; // HttpURLConnection treats empty reason as null.
List<Header> headers = new ArrayList<Header>();
for (Map.Entry<String, List<String>>field : connection.getHeaderFields().entrySet()) {
String name = field.getKey();
for (String value : field.getValue()) {
headers.add(new Header(name, value));
}
}
String mimeType = connection.getContentType();
int length = connection.getContentLength();
InputStream stream;
if (status >= 400) {
stream = connection.getErrorStream();
} else {
stream = connection.getInputStream();
}
TypedInput responseBody = new TypedInputStream(mimeType, length, stream);
return new Response(connection.getURL().toString(), status, reason, headers,responseBody);
}
private static class TypedInputStream implements TypedInput {
private final String mimeType;
private final long length;
private final InputStream stream;
private TypedInputStream(String mimeType, long length, InputStream stream) {
this.mimeType = mimeType;
this.length = length;
this.stream = stream;
}
@Override public String mimeType() {
return mimeType;
}
@Override public long length() {
return length;
}
@Override public InputStream in() throws IOException {
return stream;
}
}
}
可以看出,请求经过了打开请求,准备请求,和返回请求信息的过程,最后返回的是Response 里面包含了,请求的URL,状态,原因,和TypedInput,TypedInput里面包含了mimeType,长度,以及对应的io流。
好了,该博客系列就告一段落了。