必备知识 - Retrofit源码解析(注解反射与动态代理)

365 阅读2分钟

必备知识 - 注解反射与动态代理(Retrofit)

通过分析Retrofit的源码可以来梳理注解的进阶使用

1. Retrofit介绍

  • Retrofit 是一种用于在 Android 应用程序中进行网络请求的开源库
  • 内部封装了OKhttp,简化了网络请求的过程,并提供简易API
  • Retrofit使用了注解+反射+动态代理,让我像调用函数一样执行网路请求
  • 这个库大家都用的很熟了,无需多言,直接开始

2. API定义以及使用

public void initRetrofit(){
    //构建Retrofit,记录BaseUrl,并且构建回调线程(主线程),构建OkhttpClient
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://api.example.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    //绑定API接口,内部实现动态代理类(在动态代理类中做请求信息的拼接)
    ApiService apiService = retrofit.create(ApiService.class);

    /**
     *  函数调用时,在代理类中反射获取函数和注解信息(请求地址、请求方式、请求头、请求参数)
     *  然后将其封装成okhttp的request请求
     */

    Call<String> testCall = apiService.listRepos("test");

    //开始发起请求 -> 分发器(线程处理) -> 各种拦截器(缓存、重试、请求复用...) -> socket -> 发送 or 接收数据
    testCall.enqueue(new Callback<String>() {
        @Override
        public void onResponse(Call<String> call, Response<String> response) {  //Retrofit会将回调切到主线程

        }

        @Override
        public void onFailure(Call<String> call, Throwable t) {

        }
    });
}

3.retrofit构建流程

//构建Retrofit
public Builder() {
    this(Platform.get());  //最终会走到findPlatform函数
}

private static Platform findPlatform() {
    return "Dalvik".equals(System.getProperty("java.vm.name"))
            ? new Platform.Android() //默认走到Android环境
            : new Platform(true);
}

//绑定baseURL
public Builder baseUrl(HttpUrl baseUrl) {
    checkNotNull(baseUrl, "baseUrl == null");
    ....
    this.baseUrl = baseUrl;
    return this;
}

//构建AndroidPlatForm
static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
        return new MainThreadExecutor();
    }
    ...
    //构建主线程,对response做线程切换
    static class MainThreadExecutor implements Executor {
   
        private final Handler handler = new Handler(Looper.getMainLooper());
        
        @Override public void execute(Runnable r) {
            handler.post(r);
        }
    }
}

4.反射收集请求信息,并封装

public <T> T create(final Class<T> service) {
    return (T)  //生成代理类,上层调用函数后,走到这里,整理封装请求
            Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] {service}, new InvocationHandler() {
                        private final Platform platform = Platform.get();

                        @Override
                        public @Nullable
                        Object invoke(Object proxy, Method method, @Nullable Object[] args)
                                throws Throwable {

                            // 进行遍历方法,解析注解
                            ServiceMethod<Object, Object> serviceMethod =
                                    (ServiceMethod<Object, Object>) loadServiceMethod(method);
                            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                            return serviceMethod.callAdapter.adapt(okHttpCall);
                        }
                    });
}


//获取ServiceMethod (内部含有Okhttp的Request)
public ServiceMethod<?, ?> loadServiceMethod(Method method) {
    //读缓存,有缓存直接返回
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
        result = serviceMethodCache.get(method);
        //没缓存开始解析函数以及函数上方的注解
        if (result == null) {
            //遍历注解
            result = new ServiceMethod.Builder<>(this, method).build();
            serviceMethodCache.put(method, result);
        }
    }
    return result;
}

//解析方法头上的注解
private void parseMethodAnnotation(Annotation annotation) {
    //拼接地址  拼接请求
    if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
    }
    .....
}

//request请求信息拼接
@Override void apply(RequestBuilder builder, @Nullable T value) throws IOException {
    if (value == null) return; // Skip null values.

    String queryValue = valueConverter.convert(value);
    if (queryValue == null) return; // Skip converted but null values

    builder.addQueryParam(name, queryValue, encoded);
}

//拼接
void addQueryParam(String name, @Nullable String value, boolean encoded) {
    urlBuilder = baseUrl.newBuilder(relativeUrl);
    ....

    urlBuilder.addEncodedQueryParameter(name, value);

}

//最终会创建RequestFactory对象,将请求信息封装起来(请求方式、请求头、请求内容...)
RequestFactory(RequestFactory.Builder builder) {
    method = builder.method;  //请求函数,表示要执行的具体请求方法。
    baseUrl = builder.retrofit.baseUrl; //请求地址,表示服务器的基础URL。
    httpMethod = builder.httpMethod; //请求方式,表示请求的方法(例如GET、POST、PUT、DELETE等)。
    relativeUrl = builder.relativeUrl;  //请求的相对URL,表示请求的具体路径。
    headers = builder.headers;  // 请求头,表示请求中的头部信息。
    contentType = builder.contentType; //请求体的类型,表示请求体的媒体类型。
    hasBody = builder.hasBody;  //是否有请求体,表示请求中是否包含请求体。
    isFormEncoded = builder.isFormEncoded;// 是否为表单编码,表示请求体是否使用表单编码。
    isMultipart = builder.isMultipart;  //是否为多部分请求,表示请求体是否为多部分数据。
    parameterHandlers = builder.parameterHandlers;  //参数处理器,表示处理请求参数的具体逻辑。
    isKotlinSuspendFunction = builder.isKotlinSuspendFunction;  //是否为Kotlin挂起函数,表示请求方法是否为Kotlin的挂起函数(用于支持协程异步操作)。
}

5.发起请求,处理响应

  • okhttp请求流程
    • 创建OkhttpClient
    • 封装Request
    • 调用dispatcher(内部使用线程池做请求分发)
    • 使用拦截器来处理网路请求流程 (各个拦截器职责单一、使用责任链,层层下发)
    • response回调处理、格式转换、线程切换
//发起请求
    @Override
    public void enqueue(okhttp3.Callback responseCallback) {
        synchronized (this) {
            
            client.dispatcher().enqueue(new RealCall.AsyncCall(responseCallback));
        }
    }

//Dispatcher.java
    synchronized void enqueue(RealCall.AsyncCall call) {
        //负载均衡主要逻辑,会判断当前请求有没有上限以及同一个域名请求有没有上限,
        if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
            runningAsyncCalls.add(call);
            //线程切换 采用线程池切到子线程
            executorService().execute(call);
        } else {
            //上限了就先加到缓存队列中
            readyAsyncCalls.add(call);
        }
    }
    
    //相关限制
    private int maxRequests = 64;       //最大请求数
    private int maxRequestsPerHost = 5; //同一域名最大请求5


    //RealCall.java 各种拦截器
    okhttp3.Response getResponseWithInterceptorChain() throws IOException {
        // Build a full stack of interceptors.
        List<Interceptor> interceptors = new ArrayList<>();
        //自定义拦截器
        interceptors.addAll(client.interceptors());
        //重定向重试拦截器
        interceptors.add(retryAndFollowUpInterceptor);
        //桥接拦截器 (封装、解析HTTP格式数据)
        interceptors.add(new BridgeInterceptor(client.cookieJar()));
        //缓存拦截器 
        interceptors.add(new CacheInterceptor(client.internalCache()));
        //连接拦截器 (连接复用机制)
        interceptors.add(new ConnectInterceptor(client));
        if (!forWebSocket) {
            //自定义网络拦截器
            interceptors.addAll(client.networkInterceptors());
        }
        //请求拦截器
        interceptors.add(new CallServerInterceptor(forWebSocket));

        Interceptor.Chain chain = new RealInterceptorChain(
                interceptors, null, null, null, 0, originalRequest);
        return chain.proceed(originalRequest);
    }
    
    //ExecutorCallAdapterFactory.java
    @Override
    public void enqueue(final Callback<T> callback) {
        checkNotNull(callback, "callback == null");

        delegate.enqueue(new Callback<T>() {
            @Override public void onResponse(Call<T> call, final Response<T> response) {
                //数据回来之后切到主线程
                callbackExecutor.execute(new Runnable() {
                    @Override public void run() {
                        if (delegate.isCanceled()) {
                            callback.onFailure(ExecutorCallAdapterFactory.ExecutorCallbackCall.this, new IOException("Canceled"));
                        } else {
                            callback.onResponse(ExecutorCallAdapterFactory.ExecutorCallbackCall.this, response);
                        }
                    }
                });
            }

            @Override public void onFailure(Call<T> call, final Throwable t) {
                callbackExecutor.execute(new Runnable() {
                    @Override public void run() {
                        callback.onFailure(ExecutorCallAdapterFactory.ExecutorCallbackCall.this, t);
                    }
                });
            }
        });
    }

6.总结

  • 代理就是让三方帮我们做事情,我们不需要关心过程,只注重结果就行了,这种方式能做到单一职责,互不干扰
  • 静态代理:只能1对1,扩展性差,但是可读性强
  • 动态代理:可以1对多,扩展性强
  • 基本注解的使用告一段落了,后面对JVM虚拟机做一个学习记录。