程序员人生 网站导航

Retrofic 源码阅读

栏目:综合技术时间:2016-07-22 08:42:58

Retrofic 源码浏览

标签(空格分隔): 源码浏览

1.初识注解

  • 1.1 注解定义
    我们定义过很多接口,但在接口interface前面添加了@是甚么意思了?例如:
public @interface Get { String value() default "" ; }
  • 1.2 注解列表
    这就是注解,那末现在这个我们可以用了吗?
    答案是不是定的,还不可以用,我们必须申明这个注解用在甚么地方的才可以。
    像下面才可使用:
@Target(METHOD ) @Retention(RUNTIME ) public @interface Get { String value() default "" ; }

我们简单解释1下这个注解的意思,这个注解表示注解用于在方法上,在运行时可见,如果要用到参数上,像下面:

@Target(PARAMETER ) @Retention(RUNTIME ) public @interface Path { String value() default "" ; }

更多就请看这个类了

java.lang.annotation.ElementType

2 初识反射

  • newProxyInstance
    在JDK的api里面有1个很重要的反射方法:
/** * Returns an instance of the dynamically built class for the specified * interfaces. Method invocations on the returned instance are forwarded to * the specified invocation handler. The interfaces must be visible from the * supplied class loader; no duplicates are permitted. All non-public * interfaces must be defined in the same package. * * @param loader * the class loader that will define the proxy class * @param interfaces * an array of {@code Class} objects, each one identifying an * interface that will be implemented by the returned proxy * object * @param invocationHandler * the invocation handler that handles the dispatched method * invocations * @return a new proxy object that delegates to the handler {@code h} * @throws IllegalArgumentException * if any of the interface restrictions are violated * @throws NullPointerException * if the interfaces or any of its elements are null */ public static Object newProxyInstance (ClassLoader loader , Class<?>[] interfaces, InvocationHandler h)

我们看这个方法上面的注释
返回指定接口的动态生成类的实例。在返回的实例方法调用被转发到InvocationHandler上面。必须从所提供的类装载器可见接口;不允许任何重复。所有非公共接口必须在同1个包中定义。
也许还是没有看懂,说白了就是通过给定的接口生成1个对应的实例,这个接口的方法在实例中实现的时候被反过来调用InvocationHandler上
- InvocationHandler
所以我们需要去实现InvocationHandler类

new InvocationHandler() { @Override public Object invoke(Object proxy , Method method, Object[] args ) throws Throwable { return null; } }

很明显,你只要调用这个接口的方法,都会被反过来调用上面这个方法,
我们来看这个方法的参数
Object proxy
Method method 这个是接口方法的1些描写,里面包括对方法的各种描写。
Object[] args 就是你调用这个方式时,实际的参数。

3.通过接口反射出实例

所以整合起来,写个例子:

@Documented @Target(METHOD ) @Retention(RUNTIME ) public @interface Get { String value() default "" ; } @Documented @Target(PARAMETER ) @Retention(RUNTIME ) public @interface Path { String value() default "" ; } public interface IIterface { @Get(value="testPath" ) String testMethod( @Path ("path" )String path); } public static void main(String[] args) { IIterface test = (IIterface) Proxy.newProxyInstance(IIterface.class.getClassLoader(), new Class[] { IIterface.class }, new InvocationHandler() { @Override public Object invoke(Object proxy , Method method, Object[] args ) throws Throwable { StringBuilder sb = new StringBuilder(); method.getReturnType();// return type. Annotation[][] anss = method.getParameterAnnotations(); String pathValue = "" ; out: for (Annotation[] ans : anss) { for (Annotation an : ans) { if(an instanceof Path){ Path path = (Path)an ; pathValue = path.value(); break out; } } } Get get = method.getAnnotation(Get .class); String value = get .value(); sb.append( value).append("/" ); sb.append( pathValue).append("/" ); sb.append( args[0]); return sb .toString(); } }); String result = test .testMethod("code_path"); System. out.println(result ); }

通过这个例子,应当可以完成理解注解的使用了吧。
如果想下载完成demo

4. Retrofit2

通过上面的demo我们来看Retrofit2的代码就简单了。

4.1 何使用Retrofic2

我们在使用的时候不是先需要定义1个接口吗?
如:

public interface FusionApi { @GET("/fusion/settings/v1/users/{userId}/applications") Observable<List<CloudState>> applicationsRx(@Path("userId") String userId); }

我们创建对应的实例:

public FusionApi createFusionApi(){ Retrofit.Builder builder = new Retrofit.Builder(); builder.baseUrl(base_url); builder.addConverterFactory(GsonConverterFactory.create()); builder.addCallAdapterFactory(RxJavaCallAdapterFactory.create()); return builder.build().create(FusionApi.class); }

然后我们在使用的时候:

@Test public void applicationsRx() throws Exception { FusionService.getFusionService().setClientInfo(clientInfo); Observable<List<CloudState>> call = FusionService.getFusionService().setClientInfo(clientInfo).createFusionApi().applicationsRx(userId); call.subscribe(new Action1<List<CloudState>>() { @Override public void call(List<CloudState> cloudStates) { System.out.println(cloudStates); } }); }

固然这里使用了Observable了,下1篇我将会使用RxJava和Reconfic2的整合。
其实你看了这篇基本上都已全部使用到了,唯1少了点Observable的使用。
扯远来,回到我们的话题。

4.2 create

根据我们前面的代码,我们来看下create方法:

public <T> T create(final Class<T> service) { Utils.validateServiceInterface(service); if (validateEagerly) { eagerlyValidateMethods(service); } return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { private final Platform platform = Platform.get(); @Override public Object invoke(Object proxy, Method method, Object... args) throws Throwable { // If the method is a method from Object then defer to normal invocation. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } ServiceMethod serviceMethod = loadServiceMethod(method); OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall); } });

1行1行代码的来解释下:
第2行: 主要检测传入进来的参数是不是为interface接口
第3⑸行: 主要验证这service的方法

4.3 分析Platform.get()

接下来就是我们前面看到 需要重点分析的代码:

private final Platform platform = Platform.get();

这1行,由于Recofict2支持3个平台,android ios java8 所以在这里选择平太,很明显我们是Android平台。
看下这个方法:

static class Android extends Platform { @Override public Executor defaultCallbackExecutor() { return new MainThreadExecutor(); } @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) { return new ExecutorCallAdapterFactory(callbackExecutor); } static class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) { handler.post(r); } } }

其实看这个方法很容易理解,1个就是先了1个线程池来履行,1个主线成应当运行的的地方。想必Android入门了,就很容易理解。

4.4 分析ServiceMethod

接下来看

@Override public Object invoke(Object proxy, Method method, Object... args) throws Throwable { // If the method is a method from Object then defer to normal invocation. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } ServiceMethod serviceMethod = loadServiceMethod(method); OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall); } });

很明显前面2个if都不成立,所以我们直接来看

ServiceMethod serviceMethod = loadServiceMethod(method);

下面我们来看看 这个loadServiceMethod方法做了甚么?

ServiceMethod loadServiceMethod(Method method) { ServiceMethod result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { result = new ServiceMethod.Builder(this, method).build(); serviceMethodCache.put(method, result); } } return result; }

这个方法其实没干甚么,就是把method封装成ServiceMethod,做了1下缓存,如果有直接取,没有就重新封装1次,我们看看这个封装的方法:

result = new ServiceMethod.Builder(this, method).build(); public Builder(Retrofit retrofit, Method method) { this.retrofit = retrofit; this.method = method; this.methodAnnotations = method.getAnnotations(); this.parameterTypes = method.getGenericParameterTypes(); this.parameterAnnotationsArray = method.getParameterAnnotations(); }

第1个参数先不讲授,第2个参数先从里面读取这个方法所有的注解。
this.methodAnnotations=method.getAnnotations(); 这个是读取象Get这样1类的注解
this.parameterTypes=method.getGenericParameterTypes(); 这个读取方法的参数类型
this.parameterAnnotationsArray=method.getParameterAnnotations(); 这个读取参数里面的注解。

我们再看build方法:

public ServiceMethod build() { callAdapter = createCallAdapter(); responseType = callAdapter.responseType(); if (responseType == Response.class || responseType == okhttp3.Response.class) { throw methodError("'" + Utils.getRawType(responseType).getName() + "' is not a valid response body type. Did you mean ResponseBody?"); } responseConverter = createResponseConverter(); for (Annotation annotation : methodAnnotations) { parseMethodAnnotation(annotation); } if (httpMethod == null) { throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.)."); } if (!hasBody) { if (isMultipart) { throw methodError( "Multipart can only be specified on HTTP methods with request body (e.g., @POST)."); } if (isFormEncoded) { throw methodError("FormUrlEncoded can only be specified on HTTP methods with " + "request body (e.g., @POST)."); } } int parameterCount = parameterAnnotationsArray.length; parameterHandlers = new ParameterHandler<?>[parameterCount]; for (int p = 0; p < parameterCount; p++) { Type parameterType = parameterTypes[p]; if (Utils.hasUnresolvableType(parameterType)) { throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s", parameterType); } Annotation[] parameterAnnotations = parameterAnnotationsArray[p]; if (parameterAnnotations == null) { throw parameterError(p, "No Retrofit annotation found."); } parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations); } if (relativeUrl == null && !gotUrl) { throw methodError("Missing either @%s URL or @Url parameter.", httpMethod); } if (!isFormEncoded && !isMultipart && !hasBody && gotBody) { throw methodError("Non-body HTTP method cannot contain @Body."); } if (isFormEncoded && !gotField) { throw methodError("Form-encoded method must contain at least one @Field."); } if (isMultipart && !gotPart) { throw methodError("Multipart method must contain at least one @Part."); } return new ServiceMethod<>(this); }

先不看retrofit这个的使用,这个后面讲授:

for (Annotation annotation : methodAnnotations) { parseMethodAnnotation(annotation); }

对方法的每一个注解进行解析,我们看具体怎样解析

private void parseMethodAnnotation(Annotation annotation) { if (annotation instanceof DELETE) { parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false); } else if (annotation instanceof GET) { parseHttpMethodAndPath("GET", ((GET) annotation).value(), false); } else if (annotation instanceof HEAD) { parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false); if (!Void.class.equals(responseType)) { throw methodError("HEAD method must use Void as response type."); } } else if (annotation instanceof PATCH) { parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true); } else if (annotation instanceof POST) { parseHttpMethodAndPath("POST", ((POST) annotation).value(), true); } else if (annotation instanceof PUT) { parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true); } else if (annotation instanceof OPTIONS) { parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false); } else if (annotation instanceof HTTP) { HTTP http = (HTTP) annotation; parseHttpMethodAndPath(http.method(), http.path(), http.hasBody()); } else if (annotation instanceof retrofit2.http.Headers) { String[] headersToParse = ((retrofit2.http.Headers) annotation).value(); if (headersToParse.length == 0) { throw methodError("@Headers annotation is empty."); } headers = parseHeaders(headersToParse); } else if (annotation instanceof Multipart) { if (isFormEncoded) { throw methodError("Only one encoding annotation is allowed."); } isMultipart = true; } else if (annotation instanceof FormUrlEncoded) { if (isMultipart) { throw methodError("Only one encoding annotation is allowed."); } isFormEncoded = true; } }

其实很简单,就是对这个注解1个1个进行判断,是不是是我们已定义的注解类型。然后做了检查而已,然后标注哪些注解将被用到。
我们读其中1个注解的解析:

private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) { if (this.httpMethod != null) { throw methodError("Only one HTTP method is allowed. Found: %s and %s.", this.httpMethod, httpMethod); } this.httpMethod = httpMethod; this.hasBody = hasBody; if (value.isEmpty()) { return; } // Get the relative URL path and existing query string, if present. int question = value.indexOf('?'); if (question != -1 && question < value.length() - 1) { // Ensure the query string does not have any named parameters. String queryParams = value.substring(question + 1); Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams); if (queryParamMatcher.find()) { throw methodError("URL query string \"%s\" must not have replace block. " + "For dynamic query parameters use @Query.", queryParams); } } this.relativeUrl = value; this.relativeUrlParamNames = parsePathParameters(value); }

这个方法是读取里面的具体参数的值,然后存入到relativeUrl,relativeUrlParamNames 这里面,

static Set<String> parsePathParameters(String path) { Matcher m = PARAM_URL_REGEX.matcher(path); Set<String> patterns = new LinkedHashSet<>(); while (m.find()) { patterns.add(m.group(1)); } return patterns; }

然后我们回到开始:

OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);

这句代码,我们上面已解释了ServiceMethod这个里面有啥了。
args 是这个方法传入具体的参数值
然后看这句:

public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) { return nextCallAdapter(null, returnType, annotations); } public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) { int start = adapterFactories.indexOf(skipPast) + 1; for (int i = start, count = adapterFactories.size(); i < count; i++) { CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this); if (adapter != null) { return adapter; } } }

从这里就是取出adapter
那我们看看这adapter里面存的是甚么,然后有得到的是甚么样的callAdapter
搜素源码能看到 就是我们构造build的时候,使用这个方法添加进去的
addCallAdapterFactory我这里是 用的RxJava
固然没有添加的话,使用的是系统默许的。至于甚么时候选择哪一个,你看上面的方法就知道了,通过注解和返回类型匹配的话,就选择哪一个,如果我们返回的不是Observer类型,那我们应当是Reforcit默许的,我们看看默许的是啥?

CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) { if (callbackExecutor != null) { return new ExecutorCallAdapterFactory(callbackExecutor); } return DefaultCallAdapterFactory.INSTANCE; }

通过判断,我们没有实例callbackExecutor,应当是
所以应当是这个:

final class DefaultCallAdapterFactory extends CallAdapter.Factory {

既然找到他的实例了,我们来看看adapt 方法:

@Override public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { if (getRawType(returnType) != Call.class) { return null; } final Type responseType = Utils.getCallResponseType(returnType); return new CallAdapter<Call<?>>() { @Override public Type responseType() { return responseType; } @Override public <R> Call<R> adapt(Call<R> call) { return call; } }; }

事实也是如此。
我们传入的参数 是OkHttpCall

OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);

所以返回的是OkHttpCall ,是否是感觉转了1圈,回到出发点,啥也没干嘛?
如果那样理解那就错了。
在这里,你外面不是使用的是Call的返回参数,所以这个时候,你调用
call.execute().body(); 就得到最后的答案了吗?
所以我们跟进这个OkHttpCall来看下。

@Override public Response<T> execute() throws IOException { okhttp3.Call call; synchronized (this) { if (executed) throw new IllegalStateException("Already executed."); executed = true; if (creationFailure != null) { if (creationFailure instanceof IOException) { throw (IOException) creationFailure; } else { throw (RuntimeException) creationFailure; } } call = rawCall; if (call == null) { try { call = rawCall = createRawCall(); } catch (IOException | RuntimeException e) { creationFailure = e; throw e; } } } if (canceled) { call.cancel(); } return parseResponse(call.execute()); }

看上面的代码,重要的是2行代码,
1行是:call = rawCall = createRawCall();
那我们先看看这个方法:
createRawCall

private okhttp3.Call createRawCall() throws IOException { Request request = serviceMethod.toRequest(args); okhttp3.Call call = serviceMethod.callFactory.newCall(request); if (call == null) { throw new NullPointerException("Call.Factory returned null."); } return call; }

第1行:我们看方法:

Request toRequest(Object... args) throws IOException { RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers, contentType, hasBody, isFormEncoded, isMultipart); @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types. ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers; int argumentCount = args != null ? args.length : 0; if (argumentCount != handlers.length) { throw new IllegalArgumentException("Argument count (" + argumentCount + ") doesn't match expected count (" + handlers.length + ")"); } for (int p = 0; p < argumentCount; p++) { handlers[p].apply(requestBuilder, args[p]); } return requestBuilder.build(); } Request build() { HttpUrl url; HttpUrl.Builder urlBuilder = this.urlBuilder; if (urlBuilder != null) { url = urlBuilder.build(); } else { // No query parameters triggered builder creation, just combine the relative URL and base URL. url = baseUrl.resolve(relativeUrl); if (url == null) { throw new IllegalArgumentException( "Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl); } } RequestBody body = this.body; if (body == null) { // Try to pull from one of the builders. if (formBuilder != null) { body = formBuilder.build(); } else if (multipartBuilder != null) { body = multipartBuilder.build(); } else if (hasBody) { // Body is absent, make an empty body. body = RequestBody.create(null, new byte[0]); } } MediaType contentType = this.contentType; if (contentType != null) { if (body != null) { body = new ContentTypeOverridingRequestBody(body, contentType); } else { requestBuilder.addHeader("Content-Type", contentType.toString()); } } return requestBuilder .url(url) .method(method, body) .build();

是在这里根据参数,注解,构造了1个http要求吗?这里面就有了全部http要求的消息了。

回到原来的那个地方,我们分析第2个,如果对okhttp比较熟习的话,这就可以直接看懂了,但是我还是1直分析下去。

前面1行代码分析完了,我们来分析第2处:

parseResponse(call.execute());

call.execute(),就是根据上面全部http要求,得到了http的返回,然后再进行分析,我们来看分析的代码:

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException { ResponseBody rawBody = rawResponse.body(); // Remove the body's source (the only stateful object) so we can pass the response along. rawResponse = rawResponse.newBuilder() .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())) .build(); int code = rawResponse.code(); if (code < 200 || code >= 300) { try { // Buffer the entire body to avoid future I/O. ResponseBody bufferedBody = Utils.buffer(rawBody); return Response.error(bufferedBody, rawResponse); } finally { rawBody.close(); } } if (code == 204 || code == 205) { return Response.success(null, rawResponse); } ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody); try { T body = serviceMethod.toResponse(catchingBody); return Response.success(body, rawResponse); } catch (RuntimeException e) { // If the underlying source threw an exception, propagate that rather than indicating it was // a runtime exception. catchingBody.throwIfCaught(); throw e; } }

如果要求时成功的,则我们只需要看着两行代码:

T body = serviceMethod.toResponse(catchingBody); return Response.success(body, rawResponse);

跟入到这行代码

T toResponse(ResponseBody body) throws IOException { return responseConverter.convert(body); }

1看就知道,经过1个Converter,转换到我们想要的类型了。所以body就是我们要的封装结果。
然后以封装最后的数据类型传回了我们最初的调用端。

这里走分析源码已走了1圈了。

文章写的乱,第1次写,可能思路写的不是很清晰,后续可以需要修改。

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐