文章纯属个人学习的代码实现
网易云微专业公开课这节课 手写了这个
Retrofit
的简单实现,包含了基本的功能,能正常网络请求
我们先看一段 Retrofit
请求的基本形式,代码如下
public class RetrofitTest {
private final static String IP = "144.34.161.97";
private final static String KEY = "aa205eeb45aa76c6afe3c52151b52160";
private final static String BASE_URl = "http://apis.juhe.cn/";
interface HOST {
@GET("/ip/ipNew")
Call get(@Query("ip") String ip, @Query("key") String key);
}
@Test
public void retrofitTest() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URl)
.build();
HOST host = retrofit.create(HOST.class);
Call call = host.get(IP, KEY);
try {
Response response = call.execute();
if (response != null && response.body() != null) {
System.out.println(response.body().string());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
这里包含三个部分
第一部分
private final static String IP = "144.34.161.97";
private final static String KEY = "aa205eeb45aa76c6afe3c52151b52160";
private final static String BASE_URl = "http://apis.juhe.cn/";
这里主要是我们构建请求的一些基本变量
第二部分
interface HOST {
@GET("/ip/ipNew")
Call get(@Query("ip") String ip, @Query("key") String key);
}
熟悉Retrofit
的都知道 ,这是Retrofit
restful风格的一种请求接口约定方式
第三部分
@Test
public void retrofitTest() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URl)
.build();
HOST host = retrofit.create(HOST.class);
Call call = host.get(IP, KEY);
try {
Response response = call.execute();
if (response != null && response.body() != null) {
System.out.println(response.body().string());
}
} catch (IOException e) {
e.printStackTrace();
}
}
这里就是我们用Retrofit
构建一个基本的 请求的过程
首先我们需要一个 Retrofit
对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URl)
.build();
这里主要是通过一个工厂模式配置一些基本信息,比如请求地址的域名,可以看看合理的基本实现
public static class Builder {
private HttpUrl baseUrl;
private Call.Factory callFactory;
public Builder baseUrl(String base_uRl) {
if (base_uRl.isEmpty()){
throw new NullPointerException("baseUrl为空");
}
this.baseUrl= HttpUrl.parse(base_uRl);
return this;
}
public Builder baseUrl(HttpUrl base_uRl) {
if (base_uRl==null){
throw new NullPointerException("baseUrl为空");
}
this.baseUrl= base_uRl;
return this;
}
public Retrofit build() {
if(this.baseUrl==null){
throw new IllegalStateException("baseUrl 必须提供");
}
if(this.callFactory==null){
callFactory=new OkHttpClient();
}
return new Retrofit(this);
}
}
主要看看这个build()
方法,初始化了baseUrl
和 OkHttpClient
对象,这个是OkHttpClient
对象是用来执行Okhttp网络请求的
我们接着看着里
HOST host = retrofit.create(HOST.class);
通过我们刚刚构造出来的retrofit
对象的create
方法去返回一个 HOST
对象,我们可以看看这里怎么实现的。
public <T> T create(Class<T> t) {
return (T) Proxy.newProxyInstance(t.getClassLoader(), new Class[]{t}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在动态代理里面获取方法请求的相关参数和注解
ServiceMethod serviceMethod=loadServiceMethod(method);
//然后做请求
return new OkhttpCall(serviceMethod,args);
}
});
}
我们可以看到这其实就是动态代理,通过代理的形式实现AOP切入,在用户调用这句话Call call = host.get(IP, KEY);
的时候,这里的invoke方法 就会被调用,从而实现参数拦截,方法前后处理等功能。
而这里其实就是通过loadServiceMethod(method)
方法来完成参数和请求类型等解析。
主要方式当然是用到反射。我们可以大概看看代码
private ServiceMethod loadServiceMethod(Method method) {
//先去取 如果缓存里面有咱们就返回出去
ServiceMethod serviceMethod=serviceMethodMap.get(method);
if(serviceMethod!=null)return serviceMethod;
//如果没有 我们就需要注意线程同步问题
synchronized (serviceMethodMap){
serviceMethod=serviceMethodMap.get(method);
if(serviceMethod==null){
serviceMethod=new ServiceMethod.Builder(this,method).build();
}
}
return serviceMethod;
}
这里只做了一个取缓存里面的method的一个处理,可以看出来这里加了一个synchronized (serviceMethodMap)
防止线程同步出现问题。
核心解析参数啥的都在ServiceMethod.Builder(this,method).build()
里面,我们接着看
public Builder(Retrofit retrofit, Method method) {
this.retrofit=retrofit;
this.method=method;
this.methodAnnotations=method.getAnnotations();
this.parameterAnnotationsArray=method.getParameterAnnotations();
}
public ServiceMethod build() {
for (Annotation methodAnnotation : methodAnnotations) {
//解析方法注解 比如GET POST
parseMethodAnnotation(methodAnnotation);
}
//开始解析方法参数注解
int parameterLength = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler[parameterLength];
for (int i = 0; i < parameterLength; i++) {
//获取方法的参数的所有注解
Annotation[] annotations = parameterAnnotationsArray[i];
if(annotations == null){
throw new NullPointerException("不合规矩");
}
//开始解析Query这些参数
parameterHandlers[i] = parseParameter(i,annotations);
}
return new ServiceMethod(this);
}
我们关注这两行代码
this.methodAnnotations=method.getAnnotations();
this.parameterAnnotationsArray=method.getParameterAnnotations();
这其实就是反射里面的获取方法的注释和获取方法的参数注解。
我们再继续看看ServiceMethod
里的的核心方法
/**
* 最后要的一个方法 实际生成一个 请求对象
*/
okhttp3.Call toCall(Object... args){
//我们需要构建一个请求对象
RequestBuilder requestBuilder=new RequestBuilder(httpMethod,baseUrl,relativeUrl,hasBody);
ParameterHandler[] handlers = this.parameterHandlers;
int argumentCount=args!=null?args.length:0;
if (argumentCount != handlers.length) {
//方法真实的参数个数不等于收集的参数个数
throw new IllegalArgumentException("");
}
for (int i = 0; i < argumentCount; i++) {
//填充参数到对应的注解去
handlers[i].apply(requestBuilder,args[i].toString());
}
return callFactory.newCall(requestBuilder.build());
}
看不懂没关系,我就告诉你,是做了参数传值,然后构建了一个Request对象,然后用callFactory.newCall(requestBuilder.build());
完成请求,这个callFactory
其实就是我们Retrofit
里面传入的OkHttpClient
对象
然后我们基本就完成了请求
大家想了解更多直接去我的github看代码实现
网友评论