retrofit源码中的动态代理

225 阅读3分钟

1、retrofit简介

retrofit从诞生开始,就把其他的网络请求库给pk下去了,例如以前用了好多年的volley。他是一个优秀的网络请求框架而不是一个网络库,他需要结合okhttp来使用。 retrofit最大的特点,在于可以用一个javainterface通过注解去表示一个http请求。

(1)定义GET请求的interface

    @POST(IMAGE_URL + "/api/getUrl")
    Observable<ResponseEntity>>> getUrl(@Body CommonloadEntity params);

(2)通过retrofit创建service实例:

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("url")
.build();

(3)获取call实例执行http请求,这个地方执行的是okhttp内部的网络请求。

官方介绍他的特点的:可以用一个java interface通过注解去表示一个http请求。

2、动态代理机制

retrofit中一个非常重要的机制在于他的动态代理机制。通过上面第二步可以看出来:retrofit将一个java interfac转化为一个可以进行http请求的对象。

什么是动态代理机制?通过下面一个例子来了解下:

先定义一个java interface

interface Game {
    fun play(text:String)
}

一个interface是不可以直接创建一个对象的,所以动态代理所做的是在运行时生成一个实现了该interface的类的class对象。proxy的getProxyClass的方法注释:

Returns the {@code java.lang.Class} object for a proxy class given a class loader and an array of interfaces. The proxy class will be defined by the specified class loader and will implement all of the supplied interfaces. If any of the given interfaces is non-public, the proxy class will be non-public. If a proxy class for the same permutation of interfaces has already been defined by the class loader, then the existing proxy class will be returned; otherwise,a proxy class for those interfaces will be generated dynamically and defined by the class loader.

字面上的意思就是说,在运行时生成一个代理class二进制流,并通过传入的classLoader去加载成一个代理class对象,该class实现了传入的第二个参数对应的interface。

3、通过反射创建具体实例

val game = Proxy.getProxyClass(Game::class.java.classLoader,Game::class.java)

        val construct = game.getConstructor(InvocationHandler::class.java)
        var gameProxy = construct.newInstance(object :InvocationHandler{
            override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any {
                return "i am proxy"
            }

        })

动态代理有什么作用?结合《深入理解java虚拟机》一书中的答案:动态代理中所谓的动态,是针对使用java代码编写了代理类的静态代理而言的,它的优势不在于省去了编写代理类那一点工作量,而是实现了可以在原始类和接口还未知的时候,就确定代理类的代理行为,当代理类与原始类脱离直接联系后,就可以很灵活地重用与不同的应用场景之中。结合 retrofit来讲,就是在具体的http请求还未知的情况下,就确定了http的请求代码。

4、retrofit中的动态代理

上面的例子中,在执行创建service的时候

RetrofitService service = retrofit.create(RetrofitService.class);

这一句,虚拟机内部生成了代理类的Class二进制流,并加载到虚拟机中形成代理的class对象,再反射得到代理类对象,而该代理类实现了RetrofitService,并持有了Invocationhandler 的引用。 当调用里面的方法获取到具体的call的时候,就会调用invocationHandler引用的对象的invoke方法,并且传入RetrofitService的method对象。

InvocationHandler引用的对象的invoke方法会通过该method对象,得到方法的注解以及参数,得到http请求的链接、请求方法、请求路径、参数等请求信息,构建一个okhttp的请求并执行。

5、如何实现自己的Retrofit

(1)创建一个注解

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface HttpProxy {
    String get();
    String post();
}

(2)创建一个回调类

public interface Call<T> {
    void enqueue(CallBack<T> callBack);
}

(3)请求的回调接口

public interface CallBack<T> {
    void onResponse(T result);
    void onFailure();
}

(4)创建接口

public interface GetService {
    @HttpProxy("hello")
    Call<String> hello();
}

(5)创建相对应的实例去执行相对应的请求。