Retrofit2深度解析

    xiaoxiao2022-07-02  114

    Retrofit2深度解析

    〇、简介

    本文基于implementation 'com.squareup.retrofit2:retrofit:2.5.0' 编写而成。

    Retrofit是很好的开源项目,很好的优化了我们使用OkHttp代码,同时提供了很多强大的扩展,如RxJava。Retrofit的实现代码相对说比较少,但是他的设计思想和实现方式还是很值得大家学习。下面全面的去分析Retrofit的实现源码,有点长,可以慢慢看,有什么不足和错误可以评论。

    看着篇文章需要对一下知识有所了解:

    熟练使用Retrofit2和OKHttp3了解java高级特性反射、注解和动态代理了解设计模式了解RxJava

    每个小节基本独立,可以直接调到对应小节。

    一、初始化分析

    Retrofit2大致的使用步骤如下:

    1.初始化Retrofit

    2.构建网络请求

    3.发送请求,解析数据

    我们通过使用顺序来一步一步解析源码

    首先,看初始化的代码

    Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://mobile.weather.com.cn") .addConverterFactory(GsonConverterFactory.create()) .build();

    Retrofit的初始化采用创建者设计模式。该模式将一个复杂对象的构建与表示分离,使得用户在不知道对象的创建细节情况下就可以直接创建复杂的对象。

    a.设置base Url

    public Builder baseUrl(String baseUrl) { checkNotNull(baseUrl, "baseUrl == null"); return baseUrl(HttpUrl.get(baseUrl)); } public Builder baseUrl(HttpUrl baseUrl) { checkNotNull(baseUrl, "baseUrl == null"); List<String> pathSegments = baseUrl.pathSegments(); if (!"".equals(pathSegments.get(pathSegments.size() - 1))) { throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl); } this.baseUrl = baseUrl; return this; }

    url最终会转化为HttpUrl对象,在构建Retrofit对象时通过构造函数传入,后续操作都是通过HttpUrl完成。

    b.添加Gson数据转化器工厂

    public final class GsonConverterFactory extends Converter.Factory { public static GsonConverterFactory create() { return create(new Gson()); } @SuppressWarnings("ConstantConditions") // Guarding public API nullability. public static GsonConverterFactory create(Gson gson) { if (gson == null) throw new NullPointerException("gson == null"); return new GsonConverterFactory(gson); } private final Gson gson; private GsonConverterFactory(Gson gson) { this.gson = gson; } //响应体转换器 @Override public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type)); return new GsonResponseBodyConverter<>(gson, adapter); } //请求体转换器 @Override public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) { TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type)); return new GsonRequestBodyConverter<>(gson, adapter); } }

    GsonConverterFactory内部有响应体转化器和请求体转化器。响应体转化器的作用是将请求结果反序列化为用户返回值类型的实例对象,请求体转化器是将参数序列化为字符串来构造http协议的请求体。

    响应体转化器和请求体转化器的序列化默认公用一个对象,可以设置一个满足自己需求的Gson对象来处理复杂对象的解析。

    c.接着直接看构造出来的Retrofit的成员变量,作用写在注释里了,后面会慢慢分析他们是何处如何起作用的

    public final class Retrofit { //缓存请求方法,ServiceMethod对象存储量构建Call请求的相关信息 private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>(); //Call工厂用于创建发送的OKHttpCall对象 final okhttp3.Call.Factory callFactory; //设置公共通用url final HttpUrl baseUrl; //存储数据转换器,用于转化请求参数和响应结果 final List<Converter.Factory> converterFactories; //将创建的OKHttpCall适配成不同平台可以处理的对象,如Observable<?> final List<CallAdapter.Factory> callAdapterFactories; //切换回调结果的线程 final @Nullable Executor callbackExecutor; //是否提前检测 final boolean validateEagerly; //先省略其他代码。。。 Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl, List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories, @Nullable Executor callbackExecutor, boolean validateEagerly) { this.callFactory = callFactory; this.baseUrl = baseUrl; this.converterFactories = converterFactories; // Copy+unmodifiable at call site. this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site. this.callbackExecutor = callbackExecutor; this.validateEagerly = validateEagerly; } }

    只需要设置完Retrofit的这几个参数就算完成了初始化工作。

    d.再接着看Builder构建细节,Builder创建时关联了Platform类。Platform有两个具体的子类Java8和Android,Platform.findPlatform()根据当前环境选择合适的平台实例。不同平台有不同的默认实现类。此处默认是Android平台。

    public static final class Builder { private final Platform platform; private @Nullable okhttp3.Call.Factory callFactory; private @Nullable HttpUrl baseUrl; private final List<Converter.Factory> converterFactories = new ArrayList<>(); private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(); private @Nullable Executor callbackExecutor; private boolean validateEagerly; Builder(Platform platform) { this.platform = platform; } public Builder() { //选取适合的平台,此处为Android //具体看下面Platform的源代码 this(Platform.get()); } //省略其他代码。。。 /** * Create the {@link Retrofit} instance using the configured values. * <p> * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link * OkHttpClient} will be created and used. */ public Retrofit build() { if (baseUrl == null) { throw new IllegalStateException("Base URL required."); } // okhttp3.Call.Factory callFactory = this.callFactory; if (callFactory == null) { callFactory = new OkHttpClient(); } //②处 设置回调线程 Executor callbackExecutor = this.callbackExecutor; if (callbackExecutor == null) { callbackExecutor = platform.defaultCallbackExecutor(); } //③处 添加Call适配器工厂 // Make a defensive copy of the adapters and add the default Call adapter. List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories); callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor)); //④处 添加添加数据转换器工厂 // Make a defensive copy of the converters. List<Converter.Factory> converterFactories = new ArrayList<>( 1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize()); // Add the built-in converter factory first. This prevents overriding its behavior but also // ensures correct behavior when using converters that consume all types. converterFactories.add(new BuiltInConverters()); converterFactories.addAll(this.converterFactories); converterFactories.addAll(platform.defaultConverterFactories()); //⑤处----------------- return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories), unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly); } } class Platform { private static final Platform PLATFORM = findPlatform(); static Platform get() { return PLATFORM; } private static Platform findPlatform() { try { Class.forName("android.os.Build"); if (Build.VERSION.SDK_INT != 0) { return new Android(); } } catch (ClassNotFoundException ignored) { } try { Class.forName("java.util.Optional"); return new Java8(); } catch (ClassNotFoundException ignored) { } return new Platform(); } //省略其他不重要的代码... @IgnoreJRERequirement // Only classloaded and used on Java 8. static class Java8 extends Platform { //省略... } static class Android extends Platform { @IgnoreJRERequirement // Guarded by API check. @Override boolean isDefaultMethod(Method method) { if (Build.VERSION.SDK_INT < 24) { return false; } return method.isDefault(); } @Override public Executor defaultCallbackExecutor() { return new MainThreadExecutor(); } //默认CallAdapter适配器,ExecutorCallAdapterFactory用于切换回调函数的执行线程 //CompletableFutureCallAdapterFactory用于将Call包装成Java8的CompletableFuture<T>异步对象 @Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories( @Nullable Executor callbackExecutor) { if (callbackExecutor == null) throw new AssertionError(); ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor); return Build.VERSION.SDK_INT >= 24 ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory) : singletonList(executorFactory); } @Override int defaultCallAdapterFactoriesSize() { return Build.VERSION.SDK_INT >= 24 ? 2 : 1; } //默认转化器,将请求结果转化为Java8的Optional<T>对象 @Override List<? extends Converter.Factory> defaultConverterFactories() { return Build.VERSION.SDK_INT >= 24 ? singletonList(OptionalConverterFactory.INSTANCE) : Collections.<Converter.Factory>emptyList(); } @Override int defaultConverterFactoriesSize() { return Build.VERSION.SDK_INT >= 24 ? 1 : 0; } //用于执行回调的线程,内部只是切换到AndroidUI线程执行 static class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) { handler.post(r); } } } }

    ①处你可以通过client()或者callFactory()方法设置callFactory,OkHttpClient实现了okhttp3.Call.Factory,

    public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory

    如果没有设置callFactory默认创建一个OkHttpClient实例。OkHttpClient用于产生真正执行网络请求的Call对象。Retrofit底层网络请求还是通过OkHttp执行的,Retrofit只是用来组装用于发送请求的Call的请求参数。

    ②处Executor是用来执行回调的线程。此处platform.defaultCallbackExecutor()返回的是Android实例MainThreadExecutor的实现。

    //Platform.Android.MainThreadExecutor static class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) { handler.post(r); } }

    MainThreadExecutor主要创建了关联主线程Looper的Handler对象,用于将Runnable对象切换到主线程执行。

    ③处添加自定的和平台默认的CallAdapter.Factory对象。查看Platform.Android的defaultCallAdapterFactories(callbackExecutor)方法。

    //Platform.Android.defaultCallAdapterFactories(callbackExecutor) @Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories( @Nullable Executor callbackExecutor) { if (callbackExecutor == null) throw new AssertionError(); ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor); return Build.VERSION.SDK_INT >= 24 ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory) : singletonList(executorFactory); }

    默认创建了一个ExecutorCallAdapterFactory,该工厂主要作用是将Call转化为ExecutorCallbackCall<?>,然后将结果回调切换到callbackExecutor中执行。

    当Build.VERSION.SDK_INT >= 24 时,会再使用添加CompletableFutureCallAdapterFactory,该工程主要是将Call<?>转化为CompletableFuture<?>,承接Java8新增的强大的异步处理功能。

    后面分析到使用CallAdapter时在详细介绍他们的实现以及如何自定义。

    ④处添加添加数据转换器工厂,默认添加了BuiltInConverters和OptionalConverterFactory.INSTANCE。

    //Platform.Android.defaultConverterFactories() @Override List<? extends Converter.Factory> defaultConverterFactories() { return Build.VERSION.SDK_INT >= 24 ? singletonList(OptionalConverterFactory.INSTANCE) : Collections.<Converter.Factory>emptyList(); }

    所有字段都设置完毕Retrofit初始化完成。

    接下来看如何创建网络请求。

    二、网络请求的构建与执行

    如下是一个完成网络请求过程

    //数据结构 public class Weather { //省略 } //请求接口 public interface WeatherService { @GET("/data/sk/101010100.html") Call<Weather> getWeather(@Query("_") long timestamp); } //创建WeatherService请求接口对象 WeatherService weatherService = retrofit.create(WeatherService.class); //创建Call对象用于网络执行网络请求 Call<Weather> weatherCall = weatherService.getWeather(SystemClock.currentThreadTimeMillis()); //异步请求网络 weatherCall.enqueue(new Callback<Weather>() { @Override public void onResponse(Call<Weather> call, Response<Weather> response) { Log.d(TAG, "onResponse() called with: call = [" + call + "], response = [" + response.body().toString() + "]"); } @Override public void onFailure(Call<Weather> call, Throwable t) { Log.d(TAG, "onFailure() called with: call = [" + call + "], t = [" + t + "]"); } });

    其中最为关键一点是创建WeatherService请求接口对象,Retrofit是如何构建一个请求接口对象的,是如何构造出一个用于执行网络请求的Call对象。

    直接看retrofit.create()方法源码:

    //Retrofit.create()源码 public <T> T create(final Class<T> service) { //接口合法性校验,不能继承其他接口 Utils.validateServiceInterface(service); //validateEagerly=ture提前解析请求接口中所有已定义的方法注解的参数信息 //validateEagerly=false延时加载已定义的方法注解的参数信息,等到调用时候才解析 if (validateEagerly) { eagerlyValidateMethods(service); } //动态代理 return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { private final Platform platform = Platform.get(); private final Object[] emptyArgs = new Object[0]; @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { // 如果该方法来自Object则直接执行 if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } //如果是平台相关默认方法直接调用默认方法执行 if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } //此处真正处理接口方法信息的地方,关键内容 return loadServiceMethod(method).invoke(args != null ? args : emptyArgs); } }); }

    eagerlyValidateMethods(service)内遍历已定义的方法并调用了loadServiceMethod(method),该方法是用来提前加载接口中已定义方法的注解参数信息,并生成ServiceMethod对象缓存到Retrofit.serviceMethodCache中。

    最终通过Proxy.newProxyInstance(…)动态代理生成请求接口的子类字节码,并通过service.getClassLoader()类加载器装载到虚拟机中。最后创建并返回该类的实例化对象,该实例将接口中方法调用都传递到InvocationHandler匿名对象中进项处理。

    2.1 动态代理原理分析

    为了深刻的理解java的动态代理,我先分析下动态代理是如何实现的,后面再分析InvocationHandler中的过程。

    //生成WeatherService动态代理class字节码并保存到本地 byte[] bytes = ProxyGenerator.generateProxyClass("WeatherServiceProxy", new Class[]{WeatherService.class}); try (FileOutputStream fileOutputStream = new FileOutputStream(new File("WeatherServiceProxy.class"))) { fileOutputStream.write(bytes); fileOutputStream.flush(); }

    通过使用sun.misc.ProxyGenerator生成WeatherService动态代理的字节码,将字节码保存到本地打开可以看到如下IDE自动反编译后的字节码信息,我们可以直观的看到动态代理的实现逻辑。

    //WeatherServiceProxy.class import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import proxy.WeatherService; public final class WeatherServiceProxy extends Proxy implements WeatherService { private static Method m1; private static Method m2; private static Method m3; private static Method m0; public WeatherServiceProxy(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } //我们需要的方法 public final Call getWeather(long var1) throws { try { return (Call)super.h.invoke(this, m3, new Object[]{var1}); } catch (RuntimeException | Error var4) { throw var4; } catch (Throwable var5) { throw new UndeclaredThrowableException(var5); } } public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m2 = Class.forName("java.lang.Object").getMethod("toString"); //我们需要的方法对象 m3 = Class.forName("proxy.WeatherService").getMethod("getWeather", Long.TYPE); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }

    可以看到WeatherServiceProxy默认继承了Proxy类,这也说明了为什么Java中实现动态代理只能使用接口,因为Java是单继承并且会继承Proxy类。在看getWeather方法以及相关代码,其他方法忽略。

    //Proxy.java public class Proxy implements java.io.Serializable { //动态代理的处理对象 protected InvocationHandler h; protected Proxy(InvocationHandler h) { Objects.requireNonNull(h); this.h = h; } //其他省略。。。 } //WeatherServiceProxy的构造方法,初始化是传入一个InvocationHandler用于同一处理方法调用的逻辑 public WeatherServiceProxy(InvocationHandler var1) throws { super(var1); } //WeatherServiceProxy.getWeather的方法执行 public final Call getWeather(long var1) throws { try { //调用动态代理的InvocationHandler对象处理 return (Call)super.h.invoke(this, m3, new Object[]{var1}); } catch (RuntimeException | Error var4) { throw var4; } catch (Throwable var5) { throw new UndeclaredThrowableException(var5); } } //获取getWeather方法对象Method m3 = Class.forName("proxy.WeatherService").getMethod("getWeather", Long.TYPE);

    可以很清楚的看出来(Call)super.h.invoke(this, m3, new Object[]{var1}) 具体的处理逻辑最终由InvocationHandler对象处理。

    2.2 请求参数解析分析

    再接着看Retrofit中InvocationHandler中后面的关键内容loadServiceMethod(Method method)方法实现

    //Retrofit.loadServiceMethod方法 ServiceMethod<?> loadServiceMethod(Method method) { //获取serviceMethodCache中已经缓存的ServiceMethod,避免重复解析参数 //注意,serviceMethodCache为ConcurrentHashMap线程安全的Map实例,防止多线程访问出现问题 ServiceMethod<?> result = serviceMethodCache.get(method); if (result != null) return result; //加锁确保当前唯一访问serviceMethodCache对象,再次获取缓存值, //防止并发访问已经创建了新缓存对象,避免重复解析参数 synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { //解析方法中相关注解信息生成ServiceMethod对象,并缓存到serviceMethodCache中 result = ServiceMethod.parseAnnotations(this, method); serviceMethodCache.put(method, result); } } return result; }

    这里ServiceMethod.parseAnnotations(this, method)最终去解析所有的注解信息,所有信息都存储在ServiceMethod的实现类HttpServiceMethod中。

    //ServiceMethod.java abstract class ServiceMethod<T> { static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) { //解析请求参数生成RequestFactory用于生成okhttp3.Request RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method); //获取返回值类型 Type returnType = method.getGenericReturnType(); if (Utils.hasUnresolvableType(returnType)) { throw methodError(method, "Method return type must not include a type variable or wildcard: %s", returnType); } if (returnType == void.class) { throw methodError(method, "Service methods cannot return void."); } return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); } abstract T invoke(Object[] args); }

    解析过程分为两步,

    a.解析请求参数生成RequestFactory用于生成okhttp3.Request

    b.生成HttpServiceMethod对象用于执行具体的网络请求

    2.2.1 RequestFactory构建

    RequestFactory通过反射去解析所有的注解信息,如GET、POST、Query等,然后RequestFactory.create()创建Request。从第1处开始看

    //RequestFactory.java final class RequestFactory { static RequestFactory parseAnnotations(Retrofit retrofit, Method method) { //<--第1处,通过创建者模式构建RequestFactory对象,转到第2处-------------------- return new Builder(retrofit, method).build(); } //创建Request所有数据信息 private final Method method; private final HttpUrl baseUrl; final String httpMethod; private final @Nullable String relativeUrl; private final @Nullable Headers headers; private final @Nullable MediaType contentType; private final boolean hasBody; private final boolean isFormEncoded; private final boolean isMultipart; private final ParameterHandler<?>[] parameterHandlers; RequestFactory(Builder builder) { method = builder.method; baseUrl = builder.retrofit.baseUrl; httpMethod = builder.httpMethod; relativeUrl = builder.relativeUrl; headers = builder.headers; contentType = builder.contentType; hasBody = builder.hasBody; isFormEncoded = builder.isFormEncoded; isMultipart = builder.isMultipart; parameterHandlers = builder.parameterHandlers; } //将所有解析到的注解信息和参数信息用于构建okhttp3.Request对象 okhttp3.Request create(Object[] args) throws IOException { @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types. ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers; int argumentCount = args.length; if (argumentCount != handlers.length) { throw new IllegalArgumentException("Argument count (" + argumentCount + ") doesn't match expected count (" + handlers.length + ")"); } RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers, contentType, hasBody, isFormEncoded, isMultipart); List<Object> argumentList = new ArrayList<>(argumentCount); for (int p = 0; p < argumentCount; p++) { argumentList.add(args[p]); //将参数添加到requestBuilder中 handlers[p].apply(requestBuilder, args[p]); } return requestBuilder.get() .tag(Invocation.class, new Invocation(method, argumentList)) .build(); } static final class Builder { final Retrofit retrofit; final Method method; final Annotation[] methodAnnotations; final Annotation[][] parameterAnnotationsArray; final Type[] parameterTypes; //存储请求头信息 @Nullable ParameterHandler<?>[] parameterHandlers; //<--第2处,获取需要方法注解,参数类型列表和参数注解,供Build方法使用,转到第3处------------ Builder(Retrofit retrofit, Method method) { this.retrofit = retrofit; this.method = method; //方法上的注解如GET this.methodAnnotations = method.getAnnotations(); //方法的参数类型列表,如String.class this.parameterTypes = method.getGenericParameterTypes(); //方法的参数的注解列表,返回一个注解二维数组 this.parameterAnnotationsArray = method.getParameterAnnotations(); } //<--第3处,进行具体的解析---------------------------- RequestFactory build() { //解析方法上的注解如GET,PUT,Headers,转到第5处 for (Annotation annotation : methodAnnotations) { parseMethodAnnotation(annotation); } //<--第4处,解析方法的参数注解如Query,Path,Filed,转到第6处-------------------------- int parameterCount = parameterAnnotationsArray.length; parameterHandlers = new ParameterHandler<?>[parameterCount]; for (int p = 0; p < parameterCount; p++) { //转到第6处 parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]); } //剔除一些检测的代码。。。 return new RequestFactory(this); } //<--第5处,具体反射获取方法上的注解信息---------------------------------- private void parseMethodAnnotation(Annotation annotation) { if (annotation instanceof GET) {//省略类似的Http方法。。。 //将信息存储到到对应参数httpMethod,hasBody,relativeUrl,relativeUrlParamNames中 parseHttpMethodAndPath("GET", ((GET) annotation).value(), false); } else if (annotation instanceof retrofit2.http.Headers) { //获取请求头注解信息 String[] headersToParse = ((retrofit2.http.Headers) annotation).value(); if (headersToParse.length == 0) { throw methodError(method, "@Headers annotation is empty."); } //正则表达式解析请求头 headers = parseHeaders(headersToParse); } //省略其他注解的处理,如Http,Multipart,FormUrlEncoded } //<--第6处,具体反射获取方法参数的注解信息------------------------ private ParameterHandler<?> parseParameter(int p, Type parameterType, @Nullable Annotation[] annotations) { ParameterHandler<?> result = null; if (annotations != null) { for (Annotation annotation : annotations) { //解析参数注解,重点注意,里面用了Converter来处理请求参数,转第7处 ParameterHandler<?> annotationAction = parseParameterAnnotation(p, parameterType, annotations, annotation); //省略。。。 result = annotationAction; } } return result; } //<--第7处,解析参数注解过程,如Query,Body等。 Converter<T, R>转化器放到第三节详细说明---------- private ParameterHandler<?> parseParameterAnnotation(int p, Type type, Annotation[] annotations, Annotation annotation) { //省略其他注解解析过程,如Part,Field等 if (annotation instanceof Query) { Query query = (Query) annotation; String name = query.value(); boolean encoded = query.encoded(); //将Type类型转化成对相应的Class对象 Class<?> rawParameterType = Utils.getRawType(type); //省略其他类型的判断处理 if (rawParameterType.isArray()) { Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType()); //将参数数据转换成字符串,存储到ParameterHandler.Query中 Converter<?, String> converter = retrofit.stringConverter(arrayComponentType, annotations); return new ParameterHandler.Query<>(name, converter, encoded).array(); } else { Converter<?, String> converter = retrofit.stringConverter(type, annotations); return new ParameterHandler.Query<>(name, converter, encoded); } } else if (annotation instanceof Body) { //将参数type类型数据转换成RequestBody,存储到ParameterHandler.Body中 Converter<?, RequestBody> converter = retrofit.requestBodyConverter(type, annotations, methodAnnotations); //省略。。。 return new ParameterHandler.Body<>(converter); } return null; // Not a Retrofit annotation. } } }

    总结下RequestFactory解析方法注解和方法参数注解的过程:

    (1)RequestFactory采用创建者模式,将具体解析的过程放到RequestFactory.Builder中处理。

    (2)RequestFactory.Builder通过Method.getAnnotations获取方法上的注解,在parseMethodAnnotation进行解析,最后将结果存储到对应参数httpMethod,hasBody,relativeUrl,relativeUrlParamNames中。

    (3)RequestFactory.Builder通过method.getGenericParameterTypes获取参数类型和method.getParameterAnnotations获取参数注解,在parseParameter进行解析,最后将结果存储到对应参数ParameterHandler中。

    (4)将参数通过RequestFactory的构造器传入生成RequestFactory对象。

    (5)外部调用RequestFactory.create方法生成okhttp3.Request对象。

    注:okhttp3.Request是OkHttpClient执行网络请求的参数封装,可以看出底层网络请求的执行还是由OkHttp完成。

    2.2.2 HttpServiceMethod构建

    HttpServiceMethod相对比较简单,大部分解析工作已经被RequestFactory完成。HttpServiceMethod主要用来构建OkHttpCall对象,OkHttpCall内部依赖了okhttp3.Call对象。

    直接进入HttpServiceMethod.parseAnnotations方法

    //HttpServiceMethod.parseAnnotations方法 static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory) { //1.创建CallAdapter CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method); //合法性验证 Type responseType = callAdapter.responseType(); if (responseType == Response.class || responseType == okhttp3.Response.class) { throw methodError(method, "'" + Utils.getRawType(responseType).getName() + "' is not a valid response body type. Did you mean ResponseBody?"); } if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) { throw methodError(method, "HEAD method must use Void as response type."); } //2.创建响应体转换器 Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType); //拿到okhttp3.Call.Factory对象,此处实际为OkHttpClient对象,前面已经分析过了 okhttp3.Call.Factory callFactory = retrofit.callFactory; //3.创建HttpServiceMethod return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter); }

    逻辑很清晰,大致分为三步:

    (1)创建CallAdapter

    创建CallAdapter的过程最终由Retrofit.nextCallAdapter方法完成。

    //HttpServiceMethod.createCallAdapter方法 private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter( Retrofit retrofit, Method method) { //获取返回值参数类型 Type returnType = method.getGenericReturnType(); Annotation[] annotations = method.getAnnotations(); try { //调用retrofit.callAdapter return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations); } catch (RuntimeException e) { // Wide exception range because factories are user code. throw methodError(method, e, "Unable to create call adapter for %s", returnType); } } //Retrofit.callAdapter方法 public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) { return nextCallAdapter(null, returnType, annotations); } //Retrofit.nextCallAdapter方法 final List<CallAdapter.Factory> callAdapterFactories; public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) { checkNotNull(returnType, "returnType == null"); checkNotNull(annotations, "annotations == null"); //遍历所有的CallAdapterFactory,当adapter不为null就找到了合适的CallAdapter int start = callAdapterFactories.indexOf(skipPast) + 1;//start=0 for (int i = start, count = callAdapterFactories.size(); i < count; i++) { //此处的CallAdapterFactory具体实现逻辑放到后面章节详细讲解 CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this); if (adapter != null) { return adapter; } } //没有找到合适的CallAdapter,抛异常提示调用者 StringBuilder builder = new StringBuilder("Could not locate call adapter for ") .append(returnType) .append(".\n"); if (skipPast != null) { builder.append(" Skipped:"); for (int i = 0; i < start; i++) { builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName()); } builder.append('\n'); } builder.append(" Tried:"); for (int i = start, count = callAdapterFactories.size(); i < count; i++) { builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName()); } throw new IllegalArgumentException(builder.toString()); }

    遍历Retrofit中CallAdapter.Factory列表callAdapterFactories,当列表中有能处理returnType类型的CallAdapter即可返回。CallAdapter.Factory具体实现逻辑放到后面章节详细讲解。

    (2)创建响应体转换器

    同创建CallAdapter一样,创建响应体转换器的过程最终由Retrofit.nextResponseBodyConverter方法完成。

    //HttpServiceMethod.createResponseConverter() private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter( Retrofit retrofit, Method method, Type responseType) { Annotation[] annotations = method.getAnnotations(); try { return retrofit.responseBodyConverter(responseType, annotations); } catch (RuntimeException e) { // Wide exception range because factories are user code. throw methodError(method, e, "Unable to create converter for %s", responseType); } } //Retrofit.responseBodyConverter() public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) { return nextResponseBodyConverter(null, type, annotations); } //Retrofit.nextResponseBodyConverter() final List<Converter.Factory> converterFactories; public <T> Converter<ResponseBody, T> nextResponseBodyConverter( @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) { checkNotNull(type, "type == null"); checkNotNull(annotations, "annotations == null"); //遍历所有的converterFactories,当converter不为null就找到了合适的Converter int start = converterFactories.indexOf(skipPast) + 1; for (int i = start, count = converterFactories.size(); i < count; i++) { //此处的ConverterFactory具体实现逻辑放到后面章节详细讲解 Converter<ResponseBody, ?> converter = converterFactories.get(i).responseBodyConverter(type, annotations, this); if (converter != null) { //noinspection unchecked return (Converter<ResponseBody, T>) converter; } } //没有找到合适的Converter,抛异常提示调用者 StringBuilder builder = new StringBuilder("Could not locate ResponseBody converter for ") .append(type) .append(".\n"); if (skipPast != null) { builder.append(" Skipped:"); for (int i = 0; i < start; i++) { builder.append("\n * ").append(converterFactories.get(i).getClass().getName()); } builder.append('\n'); } builder.append(" Tried:"); for (int i = start, count = converterFactories.size(); i < count; i++) { builder.append("\n * ").append(converterFactories.get(i).getClass().getName()); } throw new IllegalArgumentException(builder.toString()); }

    遍历Retrofit中Converter.Factory列表converterFactories,当列表中有能处理type类型的Converter即可返回。Converter.Factory具体实现逻辑放到后面章节详细讲解。

    (3)创建HttpServiceMethod

    整体看下HttpServiceMethod的源码

    //HttpServiceMethod.java final class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> { static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory) { //省略。。。前面看过了 } private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter( Retrofit retrofit, Method method) { //省略。。。前面看过了 } private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter( Retrofit retrofit, Method method, Type responseType) { //省略。。。前面看过了 } private final RequestFactory requestFactory; private final okhttp3.Call.Factory callFactory; private final CallAdapter<ResponseT, ReturnT> callAdapter; private final Converter<ResponseBody, ResponseT> responseConverter; private HttpServiceMethod(RequestFactory requestFactory, okhttp3.Call.Factory callFactory, CallAdapter<ResponseT, ReturnT> callAdapter, Converter<ResponseBody, ResponseT> responseConverter) { this.requestFactory = requestFactory; this.callFactory = callFactory; this.callAdapter = callAdapter; this.responseConverter = responseConverter; } @Override ReturnT invoke(Object[] args) { //callAdapter的实现逻辑后面详细分析 return callAdapter.adapt( new OkHttpCall<>(requestFactory, args, callFactory, responseConverter)); } }

    HttpServiceMethod存储了构建OkHttpCall的相关参数,并在invoke时候创建OkHttpCall并通过callAdapter配成用户需要的类型。callAdapter的实现逻辑后面详细分析。

    接下来分析OkHttpCall,用于执行网络请求的关键代码。

    3 网络请求的执行者OkHttpCall

    前面解析各种参数,最终都传递给了OkHttpCall。所以先来看下OkHttpCall的构造函数以及成员变量:

    //OkHttpCall.java final class OkHttpCall<T> implements retrofit2.Call<T> { //前面解析的注解和参数信息 private final RequestFactory requestFactory; private final Object[] args; private final okhttp3.Call.Factory callFactory; private final Converter<ResponseBody, T> responseConverter; private volatile boolean canceled; //真正执行网络请求的对象,实际创建的对象为okhttp3.RealCall private @Nullable okhttp3.Call rawCall; private @Nullable Throwable creationFailure; private boolean executed; OkHttpCall(RequestFactory requestFactory, Object[] args, okhttp3.Call.Factory callFactory, Converter<ResponseBody, T> responseConverter) { this.requestFactory = requestFactory; this.args = args; this.callFactory = callFactory; this.responseConverter = responseConverter; } }

    可以看到OkHttpCall实现了retrofit2.Call接口,而其内部引用了okhttp3.Call。这里OkHttpCall静态代理okhttp3.Call,将所有操作代理交给rawCall执行。这样做是为了降低耦合,最大限度的隐藏内部实现细节,尽量做到对用户透明。

    在看下前面weatherCall执行的相关代码

    //异步请求网络,此处调用的是OkHttpCall.enqueue方法 weatherCall.enqueue(new Callback<Weather>() { @Override public void onResponse(Call<Weather> call, Response<Weather> response) { Log.d(TAG, "onResponse() called with: call = [" + call + "], response = [" + response.body().toString() + "]"); } @Override public void onFailure(Call<Weather> call, Throwable t) { Log.d(TAG, "onFailure() called with: call = [" + call + "], t = [" + t + "]"); } }); //OkHttpCall.enqueue @Override public void enqueue(final Callback<T> callback) { checkNotNull(callback, "callback == null"); okhttp3.Call call; Throwable failure; synchronized (this) { if (executed) throw new IllegalStateException("Already executed."); executed = true; call = rawCall; failure = creationFailure; if (call == null && failure == null) { try { //<--特别注意,此处生成okhttp3.Call对象--------------------- call = rawCall = createRawCall(); } catch (Throwable t) { throwIfFatal(t); failure = creationFailure = t; } } } if (failure != null) { callback.onFailure(this, failure); return; } if (canceled) { call.cancel(); } //通过okhttp执行网络请求 call.enqueue(new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) { Response<T> response; try { //解析响应结果,内部进行了Converter将结果转化为用户希望的类型 response = parseResponse(rawResponse); } catch (Throwable e) { throwIfFatal(e); callFailure(e); return; } try { callback.onResponse(OkHttpCall.this, response); } catch (Throwable t) { t.printStackTrace(); } } @Override public void onFailure(okhttp3.Call call, IOException e) { callFailure(e); } private void callFailure(Throwable e) { try { callback.onFailure(OkHttpCall.this, e); } catch (Throwable t) { t.printStackTrace(); } } }); } //OkHttpCall.createRawCall private okhttp3.Call createRawCall() throws IOException { //特别关注,callFactory是OkHttpClient对象,创建一个新的okhttp3.Call对象 //requestFactory.create(args)创建okhttp3.Request okhttp3.Call call = callFactory.newCall(requestFactory.create(args)); if (call == null) { throw new NullPointerException("Call.Factory returned null."); } return call; }

    分析到这里,可以看出Retrofit主要作用就是封装请求参数并产生okhttp3.Call,底层的网络请求还是由OkHttpClient去执行。Retrofit简化用户使用Okhttp的逻辑,减少了重复代码,大大提高了开发效率。

    三、Converter分析与自定义

    Converter是Retrofit用到最多的类,但是在我们使用中却很少感知,所以详细分析下Converter还是很有价值的。分析分为两步,一,Converter源码分析。二,自定义Converter。

    3.1 Converter源码分析

    所有的外部Converter获取都是通过addConverterFactory(Converter.Factory factory)设置,先看下Converter的代码实现:

    //Converter.java public interface Converter<F, T> { //用于将F类型转换成T类型 @Nullable T convert(F value) throws IOException; //根据类型和目标使用情况创建Converter实例。 abstract class Factory { //返回一个用于将HTTP响应体转化为Type的Converter,如果返回null则不能处理。 //Type的类型来自Call<SimpleResponse>中泛型的类型SimpleResponse。 public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { return null; } //返回一个用于将Type的对象转化为HTTP请求体的Converter,如果返回null则不能处理。 //Type的类型来自@Body,@Part和@PartMap中标记的参数类型。 public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) { return null; } //返回一个用于将Type的对象转化为字符串的Converter,如果返回null则不能处理。 //Type的类型来自@Field,@FieldMap,@Header,@HeaderMap,@Path,@Query //和@QueryMap中标记的参数类型。 public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations, Retrofit retrofit) { return null; } //从type中提取index处的泛型参数的上限。 //例如,Map<String, ? extends Runnable>当index=1时返回Runnable。 protected static Type getParameterUpperBound(int index, ParameterizedType type) { return Utils.getParameterUpperBound(index, type); } //从type中提取原始类类型。 //比如,List<? extends Runnable>返回List.class。 protected static Class<?> getRawType(Type type) { return Utils.getRawType(type); } } }

    通过工厂模式创建Converter,工厂模式将类的实例化延迟到具体的工厂子类中完成,有效的将使用和创建分离开来,Retrofit只负责选取合适的类型。需要其他类型的Converter时只需要添加新的Converter.Factory,这样就实现了开闭原则,达到高内聚低耦合的效果。

    通过Converter.Factory的源码可知Converter分为请求体转化器,响应体转化器和字符串转化器三类。

    在上一节中方法参数解析中有如下相关代码,从源码中直观的看下Type的获取以及Converter的使用。Type的类型直接决定Converter的作用,所以了解Type的传递过程有助于我们更好的使用Converter。

    (1)请求体转化器

    //RequestFactory.parseParameterAnnotation 中解析@Body private ParameterHandler<?> parseParameterAnnotation( int p, Type type, Annotation[] annotations, Annotation annotation) { //type来自参数类型 if (annotation instanceof Body) { //将参数type类型数据转换成RequestBody,存储到ParameterHandler.Body中 Converter<?, RequestBody> converter = retrofit.requestBodyConverter(type, annotations, methodAnnotations); //省略。。。 return new ParameterHandler.Body<>(converter); } }

    requestBodyConverter作用将Type的对象转化为HTTP请求体。

    (2)响应体转化器

    //OkHttpCall.parseResponse T body = responseConverter.convert(catchingBody); return Response.success(body, rawResponse); //HttpServiceMethod.createCallAdapter 此处将returntype传递到callAdapter中 Type returntype = method.getGenericReturnType(); //Retrofit.responseBodyConverter->Retrofit.nextResponseBodyConverter final List<Converter.Factory> converterFactories=...; Type type = callAdapter.responseType(); Converter<ResponseBody, ?> converter = converterFactories.get(i).responseBodyConverter(type, annotations, this);

    responseBodyConverter作用将HTTP响应体转化为Type对象,方便调用者使用。

    (3) 字符串转化器

    //RequestFactory.parseParameterAnnotation 中解析@Query private ParameterHandler<?> parseParameterAnnotation( int p, Type type, Annotation[] annotations, Annotation annotation) { //type来自参数类型 if (annotation instanceof Query) { Query query = (Query) annotation; String name = query.value(); boolean encoded = query.encoded(); //省略其他类型的判断处理。。。 //将参数数据转换成字符串,存储到ParameterHandler.Query中 Converter<?, String> converter = retrofit.stringConverter(type, annotations); return new ParameterHandler.Query<>(name, converter, encoded); } } //Retrofit.stringConverter public <T> Converter<T, String> stringConverter(Type type, Annotation[] annotations) { checkNotNull(type, "type == null"); checkNotNull(annotations, "annotations == null"); for (int i = 0, count = converterFactories.size(); i < count; i++) { Converter<?, String> converter = converterFactories.get(i).stringConverter(type, annotations, this); if (converter != null) { return (Converter<T, String>) converter; } } //当没有任何转化器时候,默认返回将任何类型转化为字符串的转化器 return (Converter<T, String>) BuiltInConverters.ToStringConverter.INSTANCE; }

    stringConverteryon用于将Type的对象转化为字符串,方便后续的参数处理。

    3.2 自定义Converter

    Converter只有一个方法两个泛型参数,通过convert()方法将泛型参数F转换成T。

    public interface Converter<F, T> { //用于将F类型转换成T类型 @Nullable T convert(F value) throws IOException; }

    自定义Converter只需要实现Converter.Factory中三种不同类型的转换器即可。

    Converter<ResponseBody, ?> ResponseBody转Type,判断Type类型决定是否处理该类型。Converter<?, RequestBody> Type转RequestBody,当为@Body,@Part和@PartMap标记的参数类型时触发,后判断Type类型决定是否处理该类型。Converter<?, String> Type转String,@Field,@FieldMap,@Header,@HeaderMap,@Path,@Query标记的参数类型时触发,后判断Type类型决定是否处理该类型。

    注意:Converter.Factory存储在List中,当有任何一个Converter返回直接结束循环,后面的Converter.Factory都不在访问。

    举个例子,将上面请求天气的接口改成下面的方式。

    //获取天气必要的参数信息 public class WeatherRequestModel { public long timestamp; public String city; //省略很多其他字段... } //请求接口 public interface WeatherService { @GET("/data/sk/101010100.html") //Call<Weather> getWeather(@Query("_") long timestamp); Call<Weather> getWeather(@Query("json") WeatherRequestModel weatherRequest); }

    默认执行生成如下url请求:

    并没有如期的转换成json格式,为什么尼?处理Query参数的转化器由stringConverter生成,而GsonConverterFactory没有实现该方法,默认使用了BuiltInConverters.ToStringConverter.INSTANCE中的转化器,该实现直接调用了value.toString() 。

    static final class ToStringConverter implements Converter<Object, String> { static final ToStringConverter INSTANCE = new ToStringConverter(); @Override public String convert(Object value) { return value.toString(); } }

    所以这种特殊情况时需要我们自己定义Converter处理:

    //Query2JsonConverterFactory.java public class Query2JsonConverterFactory extends Converter.Factory { private final Gson mGson; private Query2JsonConverterFactory(Gson gson) { mGson = gson; } public static Converter.Factory create() { return new Query2JsonConverterFactory(new Gson()); } public static Converter.Factory create(Gson gson) { return new Query2JsonConverterFactory(gson); } @Override public Converter<?, String> stringConverter(Type type, Annotation[] annotations, Retrofit retrofit) { //处理任何类型 return new JsonStringConverter(); } class JsonStringConverter implements Converter<Object, String> { @Override public String convert(@NonNull Object value) throws IOException { //直接通过Gson转化为json return mGson.toJson(value); } } }

    将该方法设置给Retrofit对象,再次执行生成如下url请求:

    url decode后得到:

    {“city”:“beijing”,“timestamp”:1558611883241}

    上面只是一个简单的例子,你可根据情况自定义自己需要各种ConverterFactory工厂,产生不同的Converter,并进行各种合法性验证来完善功能。

    四、CallAdapter分析与自定义

    CallAdapter顾名思义使用了适配器模式。适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

    CallAdapter是一项很重要的扩展能力,如使用RxJava。熟悉源码实现可以加深我们理解和使用Retrofit,为以后承接更高级的java功能,自定义CallAdapter打下基础。比如使用java8的CompletableFuture,Optional等新特性。

    4.1 CallAdapter源码分析

    直接看CallAdapter源代码,注释很清晰的描述了各个方法的功能。

    public interface CallAdapter<R, T> { //返回此适配器在将HTTP响应体转换为Java时使用的值类型对象。 //Call<Repo>的type是Repo,这个类型准备传递给adapt使用。 //会有不同类型的returnType传递给适配器工厂,由工厂传递给CallAdapter Type responseType(); //返回一个T类型的实例用于代理Call。 T adapt(Call<R> call); //CallAdapter工厂 abstract class Factory { //返回一个用于返回returnType类型的接口方法,如果为null则不能被该工厂处理。 public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit); //从type中提取index处的泛型参数的上限。 //例如,Map<String, ? extends Runnable>当index=1时返回Runnable。 protected static Type getParameterUpperBound(int index, ParameterizedType type) { return Utils.getParameterUpperBound(index, type); } //从type中提取原始类类型。 //比如,List<? extends Runnable>返回List.class。 protected static Class<?> getRawType(Type type) { return Utils.getRawType(type); } } }

    CallAdapter.Factory通过returnType判断是否支持该类型的适配,如果支持就返回对应实例,否自返回null。

    CallAdapter<R,T> 将Call 类型转化为T类型。

    //HttpServiceMethod.parseAnnotations CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method); //HttpServiceMethod.invoke @Override ReturnT invoke(Object[] args) { return callAdapter.adapt( new OkHttpCall<>(requestFactory, args, callFactory, responseConverter)); }

    通过上述代码源码中使用CallAdapter的情况,可以看出所有CallAdapter处理的Call对象都是OkHttpCall。OkHttpCall可以直接用于网络请求,所以可以在自定义的CallAdapter中在代理Call操作,将结果包装成用户希望的类型。

    4.2 自定义CallAdapter

    鉴于RxJava是Retrofit的官配,我们就来实现一个简易的RxJava2CallAdapterFactory适配器。

    自定义CallAdapter注意两点:

    在Factory.get判断是否支持该returnType类型,CallAdapter中返回returnType类型供Converter转换响应体数据。在CallAdapter代理Call ,先从Call 获取Response ,然后再将Response 转化为Observable,中间需要做很多合法性判断。

    举个例子,将上面请求天气的接口改成下面的方式:

    public interface WeatherService { @GET("/data/sk/101010100.html") Observable<Weather> getWeatherForRxJava(@Query("_") long timestamp); }

    很熟悉是吧,很常见的和RxJava一起使用的代码,现在我们就要实现一个自定的RxJava适配器工厂来产生RxJava的适配器。此处仅支持Observable类型,不考虑其他RxJava特性以及安全性验证等,仅实现功能。

    首先需要创建CallAdapter.Factory子类MRxJava2CallAdapterFactory,判断returnType的类型是不是Observable,不是就不处理交给下一个CallAdapter.Factory工厂处理,是就继续处理returnType的合法性,是否包含泛型参数。

    //MRxJava2CallAdapterFactory.java public class MRxJava2CallAdapterFactory extends CallAdapter.Factory { public static CallAdapter.Factory create() { return new MRxJava2CallAdapterFactory(); } @Override public CallAdapter<?, ?> get(@NonNull Type returnType, @NonNull Annotation[] annotations, @NonNull Retrofit retrofit) { Class<?> rawType = getRawType(returnType); //不符合 if (rawType != Observable.class) { return null; } //Observable必须有泛型参数 if (!(returnType instanceof ParameterizedType)) { throw new IllegalStateException("Observable return type must be parameterized" + " as Observable<Foo> or Observable<? extends Foo>"); } //拿到泛型参数,只支持一个泛型参数,其他忽略 Type responseType = getParameterUpperBound(0, (ParameterizedType) returnType); //此处传入responseType是用于给Converter转换响应体数据。 return new MRxJava2CallAdapter(responseType); } }

    符合我们预期后开始处理真正的适配,创建CallAdapter子类MRxJava2CallAdapter。MRxJava2CallAdapter主要工作是将Call 转化为Observable 。

    先大体分析下思路,用户最终需要T类型的数据,具体数据在OkHttpClient产生的响应体Response 中,所以具体操作如下:

    (1)Call 转化为 Response

    (2)判读Response 是否请求成功,是否提前取消,然后获取具体数据。

    (3)将数据T包装成Observable 返回即可。

    首先为了分离Call 和 Response 的处理逻辑先创建CallExecuteObservable类,用于得到Response 对象。

    //CallExecuteObservable.java class CallExecuteObservable<T> extends Observable<Response<T>> { Call<T> originalCall; CallExecuteObservable(Call<T> call) { this.originalCall = call; } @Override protected void subscribeActual(Observer<? super Response<T>> observer) { final Call<T> call = originalCall.clone(); //处理可以取消 Disposable disposable = new MCallDisposable(call); observer.onSubscribe(disposable); if (disposable.isDisposed()) { return; } try { //拿到Response<T> 对象通知观察 Response<T> response = call.execute(); if (!disposable.isDisposed()) { observer.onNext(response); } if (disposable.isDisposed()) { observer.onComplete(); } } catch (IOException e) { if (!disposable.isDisposed()) { observer.onError(e); } } } //处理取消Call的操作 private class MCallDisposable implements Disposable { private final Call<T> mCall; boolean isDisposed; MCallDisposable(Call<T> call) { mCall = call; } @Override public void dispose() { //处理标记,并执行取消操作 isDisposed = true; mCall.cancel(); } @Override public boolean isDisposed() { return isDisposed; } } }

    由CallExecuteObservable处理完Call 后,我们再创建一个ResponseObservable包装下CallExecuteObservable,去处理Response提取数据并进行基本的响应判断,然后直接给外部观察者T类型的数据。

    //ResponseObservable.java class ResponseObservable<T> extends Observable<T> { //包装下CallExecuteObservable对象 Observable<Response<T>> mResponseObservable; ResponseObservable(Observable<Response<T>> responseObservable) { mResponseObservable = responseObservable; } @Override protected void subscribeActual(final Observer<? super T> observer) { mResponseObservable.subscribe(new Observer<Response<T>>() { //标记请求是否执行完成 private boolean terminated; @Override public void onSubscribe(Disposable d) { observer.onSubscribe(d); } @Override public void onNext(Response<T> tResponse) { //判断请求是否成功 if (tResponse.isSuccessful()) { observer.onNext(tResponse.body()); } else { //标记是否完成,方式重复调用方法 terminated = true; Throwable throwable = new HttpException(tResponse); observer.onError(throwable); } } @Override public void onError(Throwable e) { if (!terminated) { observer.onError(e); } } @Override public void onComplete() { if (!terminated) { observer.onComplete(); } } }); } }

    经过这两层处理,用户最终拿到了T类型数据。现在创建CallAdapter子类MRxJava2CallAdapter将前面两个Observable组装起来即可。

    public class MRxJava2CallAdapter implements CallAdapter<R, Object> { private Type responseType; MRxJava2CallAdapter(Type responseType) { this.responseType = responseType; } //用于给Converter转换响应体数据。 @NonNull @Override public Type responseType() { return this.responseType; } @NonNull @Override public Object adapt(@NonNull final Call<R> call) { //组合Observable //CallExecuteObservable用于执行Call获取Response //ResponseObservable用于从Response获取数据对象 //此处 泛型R 的反序列化由GsonConverterFactory的responseBodyConverter完成 return new ResponseObservable<>(new CallExecuteObservable<>(call)); } }

    CallExecuteObservable,ResponseObservable和MRxJava2CallAdapter很简单分工明确。现在试下能否实现功能。

    public interface WeatherService { @GET("/data/sk/101010100.html") Observable<Weather> getWeatherForRxJava(@Query("_") long timestamp); } Gson gson = new Gson(); Retrofit retrofit = new Retrofit.Builder() //.addConverterFactory(Query2JsonConverterFactory.create(gson)) .addConverterFactory(GsonConverterFactory.create(gson)) //.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addCallAdapterFactory(MRxJava2CallAdapterFactory.create()) .baseUrl("http://mobile.weather.com.cn") .build(); WeatherService weatherService = retrofit.create(WeatherService.class); weatherService.getWeatherForRxJava(System.currentTimeMillis()) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe(new Observer<Weather>() { @Override public void onSubscribe(Disposable d) {} @Override public void onNext(Weather weather) { Log.d(TAG, "onNext() called with: weather = [" + weather + "]"); } @Override public void onError(Throwable e) { Log.d(TAG, "onError() called with: e = [" + e + "]"); } @Override public void onComplete() {} });

    执行结果如下,能完成转化的功能。

    上面也是一个简单的例子,想做成一个合格产品还要很多工作要做。此例子只提供实现思路,还要很多功能扩展和合法性判断可以自己去尝试。

    五、设计思想浅谈

    由于Retrofit的类间关系总体来说还是挺多挺复杂的,所以将源码中涉及到的比较重要的类间关系分成不同的功能单元做成了UML图,直观的感受下源码的组织方式,这样更容易理解大牛们为什么这样做。

    首先看下我们最接接触且的Retrofit类,下面这用例张图直观的描述了Retrofit的作用。

    InnerSystem方框内部是我随手拖进与Retrofit相关的部分类,看起来很乱很复杂。所以对于客户User来说,要想直接使用InnerSystem内部的功能难度比较大,学习成本也很高,但是User通过Retrofit类可以轻松使用这个“庞大”的系统。Retrofit类松散了客户与子系统的耦合关系,让子系统内部的模块能更容易扩展和维护,并且让子系统更加易用,客户端不再需要了解子系统内部的实现,也不需要跟众多子系统内部的模块进行交互,只需要跟Retrofit类交互就可以了。这种实现方式符合单一职责原则 专门和用户打交道,它有一个好听的名字叫外观模式。它也有缺点当内部子系统增加了新功能,那么就需要修改Retrofit类,即不符合开闭原则 。但是对于Retrofit已经足够了。

    GsonConverterFactory是我们使用最多的Retrofit扩展了,那么它又是怎么实现的呢?看下面的类图:

    熟悉工厂模式的同学一眼就可以看出Converter是采用工厂模式产生的。蓝色的Query2JsonConverterFactory是前面自定义Converter写的类。你会发现加入蓝色的部分会很容易,而且很方便的就扩展了我们想要的功能。想一想之前已经看过很多设计模式的例子,自己也写过实践过也能达到这样的效果。但是为什么尼?这是因为新的扩展是实现Converter.Factory接口,而Retrofit将该接口聚合到内部。Retrofit不依赖具体的扩展实现细节,而是靠接口约束新的扩展。这样做的好处是无论有多少的复杂扩展实现类,对于调用者Retrofit来说他们都是一样是透明的,它实现了高内聚低耦合。这里用到了依赖倒置原则 ,高层模块(调用类Retrofit)不应该依赖底层模块(实现类Query2JsonConverterFactory),二者都该依赖其抽象(Converter.Factory);抽象不应该依赖细节;细节应该依赖抽象。同理,Converter是符合依赖倒置原则 的。同时我们发现在使用Converter.Factory和Converter的时候,可以用其实子实现类无缝替换。这符合里氏替换原则 ,这也是对调用者透明的原因。再加上只需要添加新的扩展实现了就能扩展原有的功能,而不用去修改原来的代码,那么它也符合开放封闭原则 。原来使用起来如此简洁的工厂模式,却涉及了这么多的设计原则啊。嗯,简洁而不简单,这就是设计模式的威力!

    在看下CallAdapter相关类的UNL图:

    看看是不是同样的效果。

    但是这里要特别强调下CallAdapter这个适配器模式,我把它单独拿出来做了个UML图:

    额,怎么和我看过的适配器模式不太一样?来看下标准的适配器模式:

    适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。 你会发现RxJava2CallAdapter好像又符合定义,但是类图却真的不一样。但是Retrofit设计的CallAdapter符合所有设计原则的。

    那是不是设计模式出错了呢?不,设计模式没有出错,设计模式只是设计原则的体现,设计模式有一定适用范围,而设计原则才设计模式的本质,所以符合设计原则的软件设计才是好的设计,而不仅仅是符合设计模式,不要为了设计模式而是设计。设计原则是前辈们多年的经验总结,是“内功”,而设计模式是前辈们为了让我们能更使用设计原则而创造出来的“招式”。二者相辅相成才是最合理的使用方式。

    六、总结

    Retrofit源码相对比较少,逻辑也很清晰,很容易理解,但不能否然它是一个非常好的框架。一个好的框架不能仅仅停留在会用,用的熟这个层面,那这样我们对开源的利用率就太低了。这样下去,开源工具只是对我们的工作带来便利而已,并没有给我自身带来多大的提升。源码实现中还有很多更有价值的东西值得我们去探索,吸收优秀的方案,吸收优秀的思想,这才是提升我们的根本——知其然,还要知其所以然!

    纸上得来终觉浅,绝知此事要躬行。

    最新回复(0)