美文网首页
模仿一个简单的Retrofit框架

模仿一个简单的Retrofit框架

作者: JeckZyang | 来源:发表于2020-05-15 17:42 被阅读0次

    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源码详细讲解的文章,请大家关注.

    相关文章

      网友评论

          本文标题:模仿一个简单的Retrofit框架

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