美文网首页
Retrofit通过OkHttp发送请求的过程

Retrofit通过OkHttp发送请求的过程

作者: 蜗牛是不是牛 | 来源:发表于2022-04-20 21:05 被阅读0次

    retrofit是对okhttp的封装。retrofit使用注解来创建请求的,retrofit的注解有哪些,分别代表什么意义,有大量的博客都有介绍,我就不重复了。但注解创建的请求,很显然是不能被okhttp识别的,其中必定有个转换的过程。这个过程我没有搜到,所以我阅读了retrofig源码,把用注解创建的请求,变为okhttp请求的过程梳理了出来。这篇博客是分析retrofit如何生成请求,如何转换为okhttp的请求并发送出去的过程。
    源码分析基于com.squareup.retrofit2:retrofit:2.9.0

    Retrofit的使用实例

    Retrofit retrofit = new Retrofit.Builder().baseUrl("<https://api.uomg.com/>")
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    ICity iCity = retrofit.create(ICity.class);
    Call cityCall = iCity.aa("<https://node.kg.qq.com/play?s=YaCv8EYfJunVWYcH>"); // 这里url是个请求参数
    cityCall.enqueue(Callback);
    
    
    public interface ICity {
        @GET("api/get.kg")
        Call aa(@Query("songurl") String str);
        
        @FormUrlEncoded
        @POST("api/get.kg")
        Call post(@Field("songurl") String str);
    
    }
    
    

    创建请求类的对象的过程,使用了动态代理

    retrofit.create()只是创建ICity的动态代理,只有在执行iCity.aa()时,里面的InvocationHandler.invoke()才会执行。 ICity中,每一个方法都是一个请求,ICity是把这些请求封装到一个类。

    • Retrofit.java
    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 {
                                // If the method is a method from Object then defer to normal invocation.
                                if (method.getDeclaringClass() == Object.class) {
                            return method.invoke(this, args);
                                }
                                args = args != null ? args : emptyArgs;
                                return platform.isDefaultMethod(method)
                                ? platform.invokeDefaultMethod(method, service, proxy, args)
                                : loadServiceMethod(method).invoke(args);
                }
            });
    }
    
    private void validateServiceInterface(Class<?> service) {
        Platform platform = Platform.get();
        for (Method method : service.getDeclaredMethods()) {
            if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
                loadServiceMethod(method);
            }
        }
    }
    
    

    当iCity.aa()执行时,InvocationHandler.invoke()会被执行。别问为啥,动态代理就是这么干的。
    invoke()的三个入参中,Object proxy, Method method, @Nullable Object[] args,Object proxy是ICity的代理对象(细说我就不知道了);Method method是java反射中的Method,由于前面执行的是aa()方法,所以这里就是这个方法;Object[] args是aa()方法的入参。
    method.getDeclaringClass()返回的是ICity,isDefaultMethod()条件:public、非抽象、非静态,所以会走loadServiceMethod(method).invoke(args)。

    loadServiceMethod(method).invoke(args),loadServiceMethod部分

    看核心的loadServiceMethod。这段代码是从缓存中获取ServiceMethod,如果获取失败,则自己生成一个,并写入缓存。
    值得注意一点是,同步代码内重新从缓存获取了一次。

    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);
            }
        }
        return result;
    }
    
    

    下面来看ServiceMethod的生成过程。

    • ServiceMethod.java
    static ServiceMethod parseAnnotations(Retrofit retrofit, Method method) {
        RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
        return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
    }
    
    

    核心部分在HttpServiceMethod.parseAnnotations()中

    • HttpServiceMethod.java
    static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
            Retrofit retrofit, Method method, RequestFactory requestFactory) {
        /* 对kotlin支持 */
        boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
        Annotation[] annotations = method.getAnnotations();
        Type adapterType;
        if (isKotlinSuspendFunction) {
        } else {
            adapterType = method.getGenericReturnType();
        }
        CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations);
        Type responseType = callAdapter.responseType();
        Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType);
        okhttp3.Call.Factory callFactory = retrofit.callFactory;
        if (!isKotlinSuspendFunction) {
            // 疑问一、要求返回ServiceMethod,为什么返回CallAdapted
            return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); // 注意CallAdapted与前面CallAdapter,消息看错成一个类
        }
    }
    
    

    疑问一、要求返回ServiceMethod,为什么返回CallAdapted

    肯定有继承关系。具体是CallAdapted 继承于 HttpServiceMethod,HttpServiceMethod又是ServiceMethod的实现。

    class CallAdapted extends HttpServiceMethod {
    
        private final CallAdapter callAdapter;
        
        CallAdapted(
                RequestFactory requestFactory,
                okhttp3.Call.Factory callFactory,
                Converter responseConverter,
                CallAdapter callAdapter) {
            super(requestFactory, callFactory, responseConverter);
            this.callAdapter = callAdapter;
        }
    
        HttpServiceMethod {
            private final RequestFactory requestFactory;
            private final okhttp3.Call.Factory callFactory;
            private final Converter responseConverter;
    }
    
    

    loadServiceMethod(method).invoke(args),invoke部分

    入口在HttpServiceMethod.invoke

    final @Nullable ReturnT invoke(Object[] args) {
        Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
        return adapt(call, args);
    }
    
    

    这里的Call、OkHttpCall都是Retorfit自定义的类,他们在retrofit2包中,不是OkHttp的。OkHttpCall把RequestFactory、入参、callFactory、responseConverter封装起来而已。

    先不管这些入参怎么来的。HttpServiceMethod类中,adapt是抽象方法,前面的loadServiceMethod()实际返回的是CallAdapted对象,所以adapt也应该看CallAdapted的。

    • CallAdapted是内部类,HttpServiceMethod$CallAdapted.java
    protected ReturnT adapt(Call call, Object[] args) {
        return callAdapter.adapt(call);
    }
    
    

    要找到callAdapter是怎么创建的,找到这个对象的类,才能找到实现。callAdapter对象的创建,由loadServiceMethod()启动,过程在HttpServiceMethod.parseAnnotations()中,

    • HttpServiceMethod.java
    static HttpServiceMethod parseAnnotations(
        Retrofit retrofit, Method method, RequestFactory requestFactory) {
        CallAdapter callAdapter = createCallAdapter(retrofit, method, adapterType, annotations); // 不要把CallAdapter和后面的CallAdapted混淆
        if (!isKotlinSuspendFunction) {
            return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
        }
    }
    
    

    这一句 CallAdapter callAdapter = createCallAdapter(retrofit, method, adapterType, annotations); 依次调用关系:createCallAdapter 》 retrofit.callAdapter 》 nextCallAdapter,最后到

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

    这里callAdapterFactories.get(i)得到的应该是应该是Platform.defaultCallAdapterFactories()内创建的DefaultCallAdapterFactory对象,看起get()方法,这是创建CallAdapter的方法。

    • DefaultCallAdapterFactory.java
    public @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(returnType) != Call.class) {
            return null;
        }
        return new CallAdapter<Object, Call<?>>() {
            @Override
            public Type responseType() {
                return responseType;
            }
            @Override
            public Call<Object> adapt(Call<Object> call) {
                return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
            }
        };
    }
    
    

    所以上面的callAdapter,是在这儿创建的new CallAdapter()。 前面还提到的的callAdapter.adapt(),应该走到这儿来;由CallAdapter生产的Call,就是这里的ExecutorCallbackCall。判断条件分析略过。 可以看到ExecutorCallbackCall跟Call是存在继承关系的。 注意new ExecutorCallbackCall<>(executor, call)有一个入参call,ExecutorCallbackCall里面其实还是调用这个入参完成的,ExecutorCallbackCall只是充当一个代理,或者适配器的作用,真正还是参数call,即OkHttpCall。

    • ExecutorCallbackCall是内部类,详见DefaultCallAdapterFactory$ExecutorCallbackCall.java
    class ExecutorCallbackCall<T> implements Call<T> {
        final Call<T> delegate;
        ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) { // 入参call
            this.delegate = delegate;
        }
        @Override
        public void enqueue(final Callback<T> callback) {
            delegate.enqueue(Callback);
        }
    }
    
    

    请求的发送流程。Call.enqueue()

    前面Retrofit使用实例中,cityCall.enqueue,是Retrofit中的Call入列。这个Call是OkHttpCall,我们要看Retrofit的Call怎么转换为OkHttp的Call,并如入列。

    • OkHttpCall.java
    public void enqueue(final Callback<T> callback) {
        okhttp3.Call call;
        call = rawCall = createRawCall();
        call.enqueue();
    }
    
    private okhttp3.Call createRawCall() throws IOException {
        okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
        return call;
    }
    
    

    是通过这一句callFactory.newCall(requestFactory.create(args))创建的OkHttp的Call,有三个问题,1、callFactory(是okhttp3.Call.Factory)怎么创建的;2、RequestFactory的创建过程;3、RequestFactory创建OkHttp的Request的过程。

    1、callFactory(是okhttp3.Call.Factory)怎么创建的

    callFactory是okhttp中的类,用来生成okhttp中的call。下面是callFactory在retrofit各环节中的使用流程。
    1、Retrofit是用建造者模式创建的,callFactory在这里被创建,并保存为Retrofit类的成员变量。

    • Retrofit.java
    build() {
        callFactory = new OkHttpClient();
        new Retrofit(callFactory...);
    }
    
    

    2、在HttpServiceMethod.parseAnnotations()中,从retrofit中获取callFactory,并通过构造方法传递给CallAdapted。

    • HttpServiceMethod.java
    static ... parseAnnotations() {
        okhttp3.Call.Factory callFactory = retrofit.callFactory;
        new CallAdapted<>(callFactory...);
    }
    
    

    3、callFactory传递给CallAdapted后,在经由父类传递给retrofit2.Call。

    • HttpServiceMethod.java
    private final okhttp3.Call.Factory callFactory;
        HttpServiceMethod(...okhttp3.Call.Factory callFactory) {
        this.callFactory = callFactory;
    }
    
    /* callFactory是HttpServiceMethod的成员变量,由外部通过构造方法传入 */
    final @Nullable ReturnT invoke(Object[] args) {
        Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
        return adapt(call, args);
    }
    
    

    4、callFactory创建okhttp中的Call的过程。
    承上,callFactory被封装到retrofit2.Call之后,HttpServiceMethod类调用adapter()方法,实际走到CallAdapted.adapter();

    protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
        return callAdapter.adapt(call);
    }
    
    

    前面介绍过,callAdapter.adapt()生成的Call只是代理(适配器),真正的Call对象还是这个入参Call。他的真实面目在HttpServiceMethod.invoke()中

    final @Nullable ReturnT invoke(Object[] args) {
        Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    }
    
    

    这里就把callFactory传递给了Call对象。在Call.enqueue()中,用这个callFactory生成okhttp的Call。

    • OkHttpCall.java
    enquque() {
        createRawCall();
    }
    
    private okhttp3.Call createRawCall() throws IOException {
        okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
    }
    
    

    2、RequestFactory的创建过程;

    Retrofit.loadServiceMethod()调用ServiceMethod.parseAnnotations();

    • ServiceMethod.java
    static ... parseAnnotations(Retrofit retrofit, Method method) {
        RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
    }
    
    

    深入RequestFactory.parseAnnotation,看RequestFactory的创建过程,及重要的参数。

    • RequestFactory.java
    RequestFactory {
        static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
            return new Builder(retrofit, method).build();
        }
    
        RequestFactory(Builder builder) {
            method = builder.method; // java.lang.reflect.Method,对应一个请求接口,对应一个RequestFactory
            baseUrl = builder.retrofit.baseUrl; // 域名
            httpMethod = builder.httpMethod; // get、post
            relativeUrl = builder.relativeUrl; // 网关,解析接口的注解得到,详见RequestFactory.parseHttpMethodAndPath(),根源于method.getAnnotations()
            parameterHandlers = builder.parameterHandlers; // 请求参数
    ...
    }
    
        /** 建造者是内部类 */
        class Builder {
        Annotation[] methodAnnotations;
            Annotation[][] parameterAnnotationsArray;
            Builder() {
                this.methodAnnotations = method.getAnnotations(); // 获取接口方法的注解
                this.parameterTypes = method.getGenericParameterTypes();
                this.parameterAnnotationsArray = method.getParameterAnnotations(); // 获取接口方法的形式参数的注解
    }
    
            RequestFactory build() {
                for (Annotation annotation : methodAnnotations) {
                    /* 获取get|post请求方式,获取网关 */
                    parseMethodAnnotation(annotation);
                }
    
                int parameterCount = parameterAnnotationsArray.length;
                parameterHandlers = new ParameterHandler<?>[parameterCount];
                for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
                    /* 解析接口方法的参数注解,是请求参数的key、value对应 */
                    parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
                }
                return new RequestFactory(this);
            }
        }
    }
    
    

    3、RequestFactory创建OkHttp的Request的过程

    OkHttpCall.createRawCall()中,okhttp3.Call call = callFactory.newCall(requestFactory.create(args)),callFactory.newCall的入参是okhttp中的Request,requestFactory.create就是返回一个okhttp3.Request。

    • RequestFactory.java
    
    ParameterHandler[] handlers = (ParameterHandler[]) parameterHandlers;
        RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl...);
        return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
    }
    
    

    其中requestBuilder.get()是将请求的进一步处理,如全url,符合RequestBody格式的参数等。build()创建Request对象。

    相关文章

      网友评论

          本文标题:Retrofit通过OkHttp发送请求的过程

          本文链接:https://www.haomeiwen.com/subject/ltkbertx.html