zoukankan      html  css  js  c++  java
  • 【Android】Retrofit源码学习

    使用Retrofit的流程

    1. 通过Builder创建Retrofit对象:

      Retrofit retrofit = new Retrofit.Builder().baseUrl("").addConverterFactory().build();
      
    2. 用Java注解描述API

      public interface MyApi {
          @GET("/api")
          Call<Data> getData();
      }
      
    3. 通过retrofit创建api对象,并建立Call对象

      MyApi api = retrofit.create(MyApi.class);
      Call<Data> call = api.getData();
      
    4. 通过Call对象获取数据,enqueue()方法发送异步请求,同步方式则使用execute()方法

      call.enqueue(new Callback<Data>() {
          @Override
          public void onResponse(Response<ZhuanLanAuthor> author) {
              System.out.println("name: " + author.getName());
          }
          @Override
          public void onFailure(Throwable t) {
          }
      });
      

    原理解析

    Retrofit所做的事情:将Java接口翻译成HTTP请求,然后用OkHttp去发送请求。

    Retrofit使用动态代理实现了这件事

    动态代理

    动态代理可以在不实现相同接口的proxy的情况下,对相关方法进行代理。

    Java可以通过Proxy类实现代理模式,而其中的newProxyInstance() 方法可以实现动态代理。通过实现InvocationHandler接口来定义代理动作。

    • Proxy.newProxyInstance(ClassLoader, Class<?>[] interfaces,InvocationHandler)

    InvocationHandler的接口定义如下:

    public interface InvocationHandler {
        public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
    }
    

    参数含义:

    • proxy:代理对象
    • method: 代理方法
    • args: 方法的参数

    实现invoke()方法来进行代理:

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
    	// do something
        method.invoke(target, args);
        // do something
    }
    

    这样便能够成功对target方法进行代理,动态代理生成的代理类的名字为包名+$Proxy+id序号

    请求流程分析

    回到使用方法,一开始要使用create()生成API的对象

    MyApi api = retrofit.create(MyApi.class);
    

    这里看下create()的源码:

      public <T> T create(final Class<T> service) {
        validateServiceInterface(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 @Nullable Object invoke(Object proxy, Method method,
                  @Nullable Object[] args) throws Throwable {
                // 如果是Object的方法则直接调用
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                // 兼容Java8,Android平台不会调用, 确认平台的方法是通过反射机制判断类的加载信息
                if (platform.isDefaultMethod(method)) {
                  return platform.invokeDefaultMethod(method, service, proxy, args);
                }
                // 主要方法,返回ServiceMethod对象
                return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
              }
            });
      }
    

    create使用了动态代理的方法,返回了Proxy.newProxyInstance()动态代理对象

    所以api对象为动态代理对象,不是真正的实现接口产生的对象。当api对象调用getData()方法时会被动态代理拦截,然后调用InvocationHandler对象中的invoke()方法。

    然后Retrofit通过反射获取到getData()方法的注解信息,配合invoke()的args参数,创建一个ServiceMethod对象

    ServiceMethod传入Retrofit对象和Method对象,调用各个接口和解析器,最终生成一个Request,包含api的域名、path、http请求方法、请求头、body等等。最后返回一个Call对象。

    ServiceMethod<?> loadServiceMethod(Method method) {
        ServiceMethod<?> result = serviceMethodCache.get(method); // 如果有缓存则直接用
        if (result != null) return result;
    
        synchronized (serviceMethodCache) { 
            result = serviceMethodCache.get(method); // 线程安全,锁住后查看其他线程是否有加载
            if (result == null) {
                result = ServiceMethod.parseAnnotations(this, method); // 解析注解
                serviceMethodCache.put(method, result); // 放入Cache中
            }
        }
        return result;
    }
    

    跟进ServiceMethod.parseAnnotation():

    static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
        // 解析注解为HTTP请求的相关信息
        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) { //API接口方法返回值不能为void
            throw methodError(method, "Service methods cannot return void.");
        }
    
        return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
    }
    

    这里构建了一个RequestFactory对象,解析了接口中关于Http协议的相关信息,具体解析方法就是拿到Method的Annotation后instansof比较确定

    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;
        isKotlinSuspendFunction = builder.isKotlinSuspendFunction;
    }
    

    解析完后使用HttpServiceMethod.parseAnnotations()最后生成HttpServiceMethod对象

    static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
        Retrofit retrofit, Method method, RequestFactory requestFactory) {
        boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction; // kotlin支持,先忽略
        boolean continuationWantsResponse = false;
        boolean continuationBodyNullable = false;
    
        Annotation[] annotations = method.getAnnotations(); // 方法的注解 @GET @POST @DELETE等
        Type adapterType;
        // ...这里有一段关于Kotlin支持的代码,adapterType
        adapterType = method.getGenericReturnType(); // 接口方法的返回类型,一般为Call<T>
    
        CallAdapter<ResponseT, ReturnT> callAdapter =
            createCallAdapter(retrofit, method, adapterType, annotations);
        Type responseType = callAdapter.responseType();
        if (responseType == okhttp3.Response.class) {
            throw methodError(method, "'"
                              + getRawType(responseType).getName()
                              + "' is not a valid response body type. Did you mean ResponseBody?");
        }
        if (responseType == Response.class) {
            throw methodError(method, "Response must include generic type (e.g., Response<String>)");
        }
        // HEAD请求没有Response Body
        if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
            throw methodError(method, "HEAD method must use Void as response type.");
        }
    	// 设置Response的解析,可以是json解析
        Converter<ResponseBody, ResponseT> responseConverter =
            createResponseConverter(retrofit, method, responseType);
    
        okhttp3.Call.Factory callFactory = retrofit.callFactory; // 这里若是没有自定则默认为OkHttpClient
        if (!isKotlinSuspendFunction) {
            return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); // 不使用Kotlin就关注这里就行了
        }
        // ...关于Kotlin的return
    }
    

    最后返回了HttpServiceMethod的继承类CallAdapted,其中存放着RequestFactoryConverterCallFactory

    然后我们返回来看这段代码

    return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
    

    这里调用的invoke方法来为HttpServiceMethod中的invoke方法:

    @Override final @Nullable ReturnT invoke(Object[] args) {
        Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
        return adapt(call, args);
    }
    // CallAdapted中
    @Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
        return callAdapter.adapt(call);
    }
    

    这里的OKHttpCall为Okhttp3.Call的封装类,并实现了Call的相关方法enqueueexecute

    这里最后使用的adapt方法调用了Retrofit对象中的callAdapter.adapt()来对Call对象进行了适配。

    若是开始初始化Retrofit对象时没有设置CallAdapter,则回默认使用Call<T>,api接口定义时方法的返回类型只能是Call<T>

    所以便能解释如下代码:

    Call<MyData> call = api.getData();
    

    api对象为一个动态代理对象,当执行getData()时进入动态代理函数,在InvocationHandler的invoke函数最后调用了HttpServiceMethod.invoke(args),返回了一个Call<T>对象。

    响应流程分析

    Retrofit使用中最后调用自定义的API接口方法返回了Call<T>对象,这个对象实际上是Retrofit自己封装的OkHttpCall对象,随后我们使用enqueue方法发出异步请求

    call.enqueue(new CallBack<MyData>() {
        @Override
        public void onResponse(Call<MyData> call, Response<MyData> response) {
        	//... on response    
        }
        @Override
        public void onFailure(Call<MyData> call, Throwable t) {
        	//... on response    
        }
    })
    

    跟进OkHttpCall.enqueue的源码:

    @Override public void enqueue(final Callback<T> callback) {
        Objects.requireNonNull(callback, "callback == null"); // callback不能为null
    
        okhttp3.Call call; // okhttp3的Call对象
        Throwable failure;
    
        synchronized (this) { // 线程安全
            if (executed) throw new IllegalStateException("Already executed.");
            executed = true;
    
            call = rawCall; // rawCall为OkHttpCall保存的Okttp3的Call对象
            failure = creationFailure;
            if (call == null && failure == null) {
                try {
                    // createRawCall中使用callFactory.newCall(requestFactory.create(args))
                    // 实际上就是OkHttpClient.newCall(OkHttp3.Request)
                    // 返回了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();
        }
    	// 使用okhttp3.Call的enqueue方法
        call.enqueue(new okhttp3.Callback() {
            @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)			{
                Response<T> response;
                try {
                    // 这里使用了Converter来解析Response
                    // 将Okhttp3.Response对象解析成Retrofit封装的Response对象
                    response = parseResponse(rawResponse);
                } catch (Throwable e) {
                    throwIfFatal(e);
                    callFailure(e);
                    return;
                }
    
                try {
                    // 调用传进来的回调
                    callback.onResponse(OkHttpCall.this, response);
                } catch (Throwable t) {
                    throwIfFatal(t);
                    t.printStackTrace();
                }
            }
    
            @Override public void onFailure(okhttp3.Call call, IOException e) {
                callFailure(e);
            }
    		// 请求失败则进入callback的OnFailure方法
            private void callFailure(Throwable e) {
                try {
                    callback.onFailure(OkHttpCall.this, e);
                } catch (Throwable t) {
                    throwIfFatal(t);
                    t.printStackTrace();
                }
            }
        });
    }
    

    其中parseResponse()方法:

    Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
        ResponseBody rawBody = rawResponse.body();
    
        // 将Response Body 和 ResponseHeader 分开
        // 之后再对Body进行处理
        rawResponse = rawResponse.newBuilder()
            .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
            .build();
    
        int code = rawResponse.code(); // HTTP 状态码
        // 响应不成功
        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();
            }
        }
    	// 响应无内容,填入null
        if (code == 204 || code == 205) {
            rawBody.close();
            return Response.success(null, rawResponse);
        }
    	// 保存source的Response Body,在解析失败时可以使用
        ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
        try {
            // 使用responseConverter来解析Body
            T body = responseConverter.convert(catchingBody);
            // 将解析好的Body装入Retrofit的Response对象返回
            return Response.success(body, rawResponse);
        } catch (RuntimeException e) {
            catchingBody.throwIfCaught();
            throw e;
        }
    }
    

    主要的parse过程便是,将Okhttp.Response对象的Body和Header拆开,若请求成功且Body有内容则将Body交给responseConverter取解析成响应对象,装入Retrofit的Response对象中返回。

    总结

    1. Retrofit的特色:通过使用注解定义API接口的方式声明API,通过注解的解析,将解析得到的信息封装在RequestFactory中,在使用时调用create()方法生成Okhttp的Request对象。
    2. 通过动态代理的方式,代理用户定义的API接口方法,使其生成封装的OkHttpCall对象
    3. 封装okhttp.Call为OkHttpCall,使其能够使用CallAdapter(可以使返回的Call对象适配为其他的对象,如RxJava(没用过)中的对象)和ResponseConverter(支持Gson等解析)
    4. 目前只读到这里,还有一些机制没读完

    参考文章

    https://www.jianshu.com/p/c1a3a881a144

    https://segmentfault.com/a/1190000006767113

    https://yq.aliyun.com/articles/658544

  • 相关阅读:
    Javaweb之 servlet 开发具体解释1
    struts2_6_多个struts配置文件的应用
    PHP多种序列化/反序列化的方法
    CF459C Pashmak and Buses 打印全排列
    HDOJ 题目3564 Another LIS(线段树单点更新,LIS)
    Android UI开发第四十三篇——使用Property Animation实现墨迹天气3.0引导界面及动画实现
    [ACM] HDU 1533 Going Home (二分图最小权匹配,KM算法)
    POJ 3895 Cycles of Lanes (dfs)
    【iOS开发-51】案例学习:动画新写法、删除子视图、视图顺序、延迟方法、button多功能使用方法及icon图标和启动页设置
    iOS-代理托付的使用
  • 原文地址:https://www.cnblogs.com/y4ngyy/p/12530566.html
Copyright © 2011-2022 走看看