模仿一个简单的Retrofit框架

2020-05-15  本文已影响0人  JeckZyang

Retrofit是一个Restful的HTTP网络 请求框架的封装,网络请求的工作本质是由OkHttp完成, 而Retrofit仅负责完了请求和接口的封装.

在Retrofit底层其实运用了反射,注解,动态代理等技术,网络工作的完成,完全是由okhttp3.Call.Factory,经过源码分析, Factory只是一个接口,他只有唯一实现类,那就是我们熟悉的OkHttpClient,一般我们通过OkHttpClient完成网络参数的配置,例如请求超时时间等等...

在这里我们来模仿一个简单的Retrofit,有利于后面研究Retrofit和OkHttp源码.其中不包含converterFactories,callAdapterFactories等功能,


image.png

老规矩,先上效果图.

File: WeatherApi.java

import com.zyang.simpleretrofit.retrofit.annotaion.Field;
import com.zyang.simpleretrofit.retrofit.annotaion.GET;
import com.zyang.simpleretrofit.retrofit.annotaion.POST;
import com.zyang.simpleretrofit.retrofit.annotaion.Query;

import okhttp3.Call;

public interface WeatherApi {

    @POST("/v3/weather/watherInfo")
    Call postWeather(@Field("city")String city, @Field("key")String key);

    @GET("/v3/weather/watherInfo")
    Call getWeather(@Query("city") String city, @Query("key")String key);

}
      ZyangRetrofit zyangRetrofit = new ZyangRetrofit.Builder()
                .baseUrl("https://restapi.amap.com")
                .build();

       weatherApi = zyangRetrofit.create(WeatherApi.class);
       okhttp3.Call call = weatherApi.getWeather("110101", "ae6c53e2186f33bbf240a12d80672d1b");
       call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.i(TAG, "onResponse: onFailure"+e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                Log.i(TAG, "onResponse: get: "+response.body().string());
                response.close();
            }
        });

接下来就是框架的编写了.

1,导入okHttp相关资源包,不是Retrofit资源包
 implementation 'com.squareup.okhttp3:okhttp:3.14.7'
2,编写Annotaion(注解)Field,GET,POST,Query.关于注解的知识大家可以看java注解这篇文章.
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Field {
    String value() ;
}
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Query {
    String value();
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GET {
    String value() default "";
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface POST {
    String value() default "";
}

3,编写ZyangRetrofit 类里面的createa()方法.在createa方法里面采用的是动态代理,主要职责是通过我们自己定义的WatherApi接口,动态创建创建WatherApi的代理对象,其实就是实现WatherApi接口的类.

    //通过动态代理构建service接口的代理对象.
    public <T> T create(final Class<T> service){
        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        ServiceMethod serviceMethod = loadServiceMethod(method);
                        return serviceMethod.invoke(args);
                    }
                });
    }

4,通过动态代理的InvocationHandler()接口中的invoke方法,去返回我们代理的对象. 首先编写ServiceMethod类.在ServiceMethod类主要是通过反射去解析接口方法和方法参数上面的注解,然后构建网络请求的环境. 最终通过OkHttp去完成网络请求的动作.


import com.zyang.simpleretrofit.retrofit.annotaion.Field;
import com.zyang.simpleretrofit.retrofit.annotaion.GET;
import com.zyang.simpleretrofit.retrofit.annotaion.POST;
import com.zyang.simpleretrofit.retrofit.annotaion.Query;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.Request;

/**
 */
public class ServiceMethod {
    private final okhttp3.Call.Factory callFactory;
    private HttpUrl baseUrl;
    private String httpMethod;
    private final String relativeUrl;
    private FormBody.Builder formBuild;
    private HttpUrl.Builder urlBuilder;

    private final ParameterHandler[] parameterHandlers;


    public ServiceMethod(Builder builder) {
        callFactory = builder.zyangRetrofit.callFactory;
        baseUrl = builder.zyangRetrofit.baseUrl;

        httpMethod = builder.httpMethod;
        relativeUrl = builder.relativeUrl;

        parameterHandlers = builder.parameterHandlers;

        if (builder.hashBody){
            formBuild = new FormBody.Builder();
        } // 到这里构建已经完成差不多了
    }

    public Object invoke(Object[] args) {
        /*
        1,处理请求的地址与参数
         */
        for (int i = 0; i < parameterHandlers.length; i++) {
            ParameterHandler handlers = parameterHandlers[i];
            handlers.apply(this,args[i].toString());
        }
        HttpUrl url;
        //获取最终请求地址
        if (urlBuilder == null) {
            urlBuilder = baseUrl.newBuilder(relativeUrl);
        }
        url = urlBuilder.build();

        FormBody formBody = null;
        if (formBuild != null){
            formBody = formBuild.build();
        }

        Request request = new Request.Builder()
                .url(url).method(httpMethod,formBody).build();

        return callFactory.newCall(request);
    }


    public void addQueryParameterHandler(String key, String value) {
        if (urlBuilder == null) {
            urlBuilder = baseUrl.newBuilder(relativeUrl);
        }
        urlBuilder.addQueryParameter(key,value);
    }

    public void addFiledParameter(String key, String value) {
        formBuild.add(key,value);
    }


    public static final class Builder {
        private final ZyangRetrofit zyangRetrofit;
        private final Annotation[] methodAnnotations;
        private final Annotation[][] parameterAnnotations;
        private String httpMethod;
        private String relativeUrl;
        private boolean hashBody;
        private ParameterHandler[] parameterHandlers;

        public Builder(ZyangRetrofit zyangRetrofit, Method method) {
            this.zyangRetrofit = zyangRetrofit;
            //获取方法上所有的注解
            methodAnnotations  = method.getAnnotations();
            // 获取方法参数的所有的注解(一个参数可以有多个注解, 一个方法又会有多个参数)
            parameterAnnotations = method.getParameterAnnotations();
        }

        public ServiceMethod build(){
            /*
                todo:1,解析方法上的所有注解, 只处理POST与GET
             */
            for (Annotation methodAnnotation : methodAnnotations) {
                if (methodAnnotation instanceof POST){
                    this.httpMethod = "post";
                    this.relativeUrl = ((POST) methodAnnotation).value();
                    //是否有请求体, POST请求, 参数都是请求中
                    this.hashBody = true;
                }else if (methodAnnotation instanceof GET){
                    this.httpMethod = "GET";
                    this.relativeUrl = ((GET) methodAnnotation).value();
                    this.hashBody = false;
                }
            }
            /*
            todo:2,解析方法参数上面的注解
             */
            int length = parameterAnnotations.length;
            parameterHandlers = new ParameterHandler[length];
            for (int i = 0; i < length; i++) {
                //一个参数上所有的注解
                Annotation[] annotations = parameterAnnotations[i];
                for (Annotation annotation : annotations) {
                    if (annotation instanceof Field) {
                        String value = ((Field) annotation).value();
                        parameterHandlers[i] = new ParameterHandler.FiledParameterHandler(value);
                    }else if (annotation instanceof Query){
                        String value = ((Query) annotation).value();
                        parameterHandlers[i] = new ParameterHandler.QueryParameterHandler(value);
                    }

                }
            }
            return new ServiceMethod(this);
        }
    }
}

5,在ServiceMethod类里面还要需要对请求参数请求处理, 需要编写ParameterHandler类.
public abstract class ParameterHandler {
    protected String key;
    abstract void apply(ServiceMethod serviceMethod,String value);


    static class QueryParameterHandler extends ParameterHandler{
        public QueryParameterHandler(String key) {
            this.key = key;
        }

        @Override
        void apply(ServiceMethod serviceMethod, String value) {
          serviceMethod.addQueryParameterHandler(key,value);
        }
    }



    static class FiledParameterHandler extends ParameterHandler{
        public FiledParameterHandler(String key) {
            this.key = key;
        }

        @Override
        void apply(ServiceMethod serviceMethod, String value) {
            serviceMethod.addFiledParameter(key,value);
        }
    }
}
5,通过ZyangRetrofit类里面的调用 serviceMethod.invoke(args)的 方法,这个方法最终返回的是代理对象, 通过okhttp创建callFactory.newCall(request) 并返回
6,最后把ZyangRetrofit源码展示如下

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import okhttp3.Call;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;

public class ZyangRetrofit {

// 因为在okhttp 需要一个 callFactory 例如 OkHttpClient();
final Call.Factory callFactory;

//这是okHttp url格式的baseUrl
final HttpUrl baseUrl;

final Map<Method,ServiceMethod> serviceMethodMap = new ConcurrentHashMap<>();


protected ZyangRetrofit(Call.Factory callFactory,HttpUrl baseUrl){
    this.callFactory = callFactory;
    this.baseUrl = baseUrl;
}

//通过动态代理构建service接口的代理对象.
public <T> T create(final Class<T> service){
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service},
            new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    ServiceMethod serviceMethod = loadServiceMethod(method);
                    return serviceMethod.invoke(args);
                }
            });
}

/*
获取Method解析后的信息
 */
private ServiceMethod loadServiceMethod(Method method) {
    ServiceMethod resultService = serviceMethodMap.get(method);
    if (resultService != null){
        return resultService;
    }
    synchronized (serviceMethodMap){
        resultService = serviceMethodMap.get(method);
        if (resultService == null){
            resultService = new ServiceMethod.Builder(this,method).build();
            serviceMethodMap.put(method,resultService);
        }
    }
    return resultService;
}

/**
 * 构建者模式, 将一个复杂对象的构建和本体进行分离, 可以使使用者不必知道内部组成的细节
 */
public static final class Builder{

    private HttpUrl baseUrl;

    //okhttp3.Call.Factory 有唯一一个实现类, 是OkhttpClient
    private okhttp3.Call.Factory callFactory;

    public Builder callFactory(okhttp3.Call.Factory factory){
        this.callFactory = factory;
        return this;
    }

    public Builder baseUrl(String baseUrl){
        this.baseUrl = HttpUrl.get(baseUrl);
        return this;
    }

    public ZyangRetrofit build(){
        if (baseUrl == null){
            throw new IllegalStateException("Base URL required");
        }
        okhttp3.Call.Factory callFactory = this.callFactory;
        if (callFactory == null){
            callFactory = new OkHttpClient();
        }
        return new ZyangRetrofit(callFactory,baseUrl);
    }
}

}

总结, 上面的框架,大都是采用构建者模式,通过Builder去构建对象.

下面是框架的类图.


retrofit2.png

时序图


image.png

以上是模仿一个简单的Retrofit. 后面会有针对Retrofit源码详细讲解的文章,请大家关注.

上一篇下一篇

猜你喜欢

热点阅读