本篇就开始对LQHttpRetrofit是如何实现的解析---更多的是去看代码注释解析
本篇只是带着过一下,具体工程已上传到gitlib,gitlab地址在本篇末尾有链接
先看项目的基本目录接口(旨在解析Retrofit的实现思路,所以只实现了一个基本的)
首先看LqRetrofit类的实现解析:
看代码
public class LQRetrofit {
//缓存MethodAnnotationInfo容器
private final ConcurrentHashMap<String, MethodAnnotationInfo> methodAnnotationInfoCache = new ConcurrentHashMap<>();
//实现真正的网络请求的适配器
private LQHttpAdapter lqHttpAdapter;
//配置的基本url地址
private String baseUrl;
private LQRetrofit(Builder builder) {
this.lqHttpAdapter = builder.getLQHttpAdapter();
this.baseUrl = builder.getBaseUrl();
}
public String getBaseUrl() {
return baseUrl;
}
public <T> T create(Class<T> service) {
//验证service是否是接口 且接口中要有方法
Util.validateServiceInterface(service);
//使用动态代理
ClassLoader classLoader = service.getClassLoader();
Class[] classes = {service};
InvocationHandler invocationHandler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//如果是在Object类中声明的方法(也就是自己实现了),就直接调用
if (method.getDeclaringClass() == Object.class) {
return method.invoke(proxy, args);
} else if (method.isDefault()) { //如果是接口中定义的默认方法 抛出异常
return Util.invokeDefaultMethod(method, service, proxy, args);
} else { //开始实现LQRetrofit
//获取方法返回值的全类名
Type genericReturnType = method.getGenericReturnType();
// 判断返回值的类型是否是参数化类型
if (genericReturnType instanceof ParameterizedType) {
//获取MethodAnnotationInfo 先从缓存中拿,没拿到就去解析再获取
MethodAnnotationInfo methodAnnotationInfo = getMethodAnnotationInfo(method, args, genericReturnType);
//返回Call结果值
return new Call<>(lqHttpAdapter, methodAnnotationInfo);
} else {
throw new IllegalStateException("The return value type of the method must be the Call<T> type");
}
}
}
};
return (T) Proxy.newProxyInstance(classLoader, classes, invocationHandler);
}
/**
* 获取解析后的MethodAnnotationInfo
*
* @param method 方法
* @param args 方法参数
* @param genericReturnType 接口返回值类型
* @return
*/
public MethodAnnotationInfo getMethodAnnotationInfo(Method method, Object[] args, Type genericReturnType) {
String methodName = method.getName();
MethodAnnotationInfo annotationInfo = methodAnnotationInfoCache.get(methodName);
if (annotationInfo != null) {
return annotationInfo;
} else {
MethodAnnotationInfo methodAnnotationInfo = parseMethodAnnotationInfo(method, args, genericReturnType);
methodAnnotationInfoCache.put(methodName, methodAnnotationInfo);
return methodAnnotationInfo;
}
}
/**
* 解析接口方法中的注解
*
* @param method 方法
* @param args 方法参数
* @return
*/
public MethodAnnotationInfo parseMethodAnnotationInfo(Method method, Object[] args, Type genericReturnType) {
//获取调用接口方法上的所有注解
Annotation[] methodAnnotations = method.getAnnotations();
//解析方法上的所有注解
if (methodAnnotations.length < 1) {
throw new IllegalStateException("Please specify @GET or @POST or @PUT or @DELETE");
}
ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;
Type[] typeArguments = parameterizedType.getActualTypeArguments();// 返回表示此类型实际类型参数的 Type 对象的数组
Type resultType = typeArguments[0];//接口获取返回值的类型
//实例化MethodAnnotationInfo
MethodAnnotationInfo annotationInfo = new MethodAnnotationInfo();
annotationInfo.setResultType(resultType);
for (Annotation annotation : methodAnnotations) {
if (annotation instanceof GET) {
annotationInfo.setRequestType(RequestType.GET);
String url = ((GET) annotation).value();
if (((GET) annotation).useBaseUrl()) {
url = getBaseUrl() + url;
}
annotationInfo.setUrl(url);
} else if (annotation instanceof POST) {
annotationInfo.setRequestType(RequestType.POST);
String url = ((POST) annotation).value();
if (((POST) annotation).useBaseUrl()) {
url = getBaseUrl() + url;
}
annotationInfo.setUrl(url);
} else if (annotation instanceof DELETE) {
annotationInfo.setRequestType(RequestType.DELETE);
String url = ((DELETE) annotation).value();
if (((DELETE) annotation).useBaseUrl()) {
url = getBaseUrl() + url;
}
annotationInfo.setUrl(url);
} else if (annotation instanceof PUT) {
annotationInfo.setRequestType(RequestType.PUT);
String url = ((PUT) annotation).value();
if (((PUT) annotation).useBaseUrl()) {
url = getBaseUrl() + url;
}
annotationInfo.setUrl(url);
} else if (annotation instanceof PATCH) {
annotationInfo.setRequestType(RequestType.PATCH);
String url = ((PATCH) annotation).value();
if (((PATCH) annotation).useBaseUrl()) {
url = getBaseUrl() + url;
}
annotationInfo.setUrl(url);
} else if (annotation instanceof HEAD) {
annotationInfo.setRequestType(RequestType.HEAD);
String url = ((HEAD) annotation).value();
if (((HEAD) annotation).useBaseUrl()) {
url = getBaseUrl() + url;
}
annotationInfo.setUrl(url);
} else if (annotation instanceof OPTIONS) {
annotationInfo.setRequestType(RequestType.OPTIONS);
String url = ((OPTIONS) annotation).value();
if (((OPTIONS) annotation).useBaseUrl()) {
url = getBaseUrl() + url;
}
annotationInfo.setUrl(url);
} else if (annotation instanceof Headers) {
String[] headers = ((Headers) annotation).value();
if (headers.length > 0) {
for (String header : headers) {
String[] split = header.split(":");
if (split.length != 2) {
throw new IllegalArgumentException("Designated header is not standard");
} else {
annotationInfo.addHeader(split[0], split[1]);
}
}
} else {
throw new NullPointerException("Headers is not null");
}
}
}
//解析方法中的参数注解
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
if (parameterAnnotations.length > 0) {
for (int i = 0; i < parameterAnnotations.length; i++) {
Annotation[] parameterAnnotation = parameterAnnotations[i];
Annotation annotation = parameterAnnotation[0];
if (annotation instanceof Header) {
String key = ((Header) annotation).value();
annotationInfo.addHeader(key, args[i] + "");
} else if (annotation instanceof Body) {
annotationInfo.setBody(args[i] + "");
} else if (annotation instanceof Param) {
String key = ((Param) annotation).value();
annotationInfo.addParam(key, args[i] + "");
} else if (annotation instanceof PathVariable) {
annotationInfo.addPath(new KVEntry<>(((PathVariable) annotation).value(),
args[i] + ""));
}
}
}
return annotationInfo;
}
public static class Builder {
private String baseUrl = "";
private LQHttpAdapter lqHttpAdapter;
public Builder(LQHttpAdapter lqHttpAdapter) {
this.lqHttpAdapter = lqHttpAdapter;
}
String getBaseUrl() {
return baseUrl;
}
public Builder setBaseUrl(String baseUrl) {
this.baseUrl = Util.strIsEmpty(baseUrl) ? "" : baseUrl;
return this;
}
LQHttpAdapter getLQHttpAdapter() {
return lqHttpAdapter;
}
public LQRetrofit build() {
return new LQRetrofit(this);
}
}
}
看MethodAnnotationInfo类:
/**
* 最终请求的信息(也就是注解信息)
*/
public class MethodAnnotationInfo implements Serializable {
private static final long serialVersionUID = 1L;
//请求方式
private String requestType;
//请求url地址
private String url;
//添加请求头
private LinkedHashMap<String, String> headers;
//添加请求体
private String body;
//请求参数
private Map<String, String> params;
//返回值类型
private Type resultType;
//组拼的url路径
private LinkedList<KVEntry<String, String>> paths;
public Type getResultType() {
return resultType;
}
void setResultType(Type resultType) {
this.resultType = resultType;
}
public Map<String, String> getHeaders() {
return headers;
}
void addHeader(String key, String value) {
if (headers == null) {
headers = new LinkedHashMap<>();
}
this.headers.put(key, value);
}
void addParam(String key, String value) {
if (params == null) {
params = new HashMap<>();
}
this.params.put(key, value);
}
public Map<String, String> getParams() {
return params;
}
public String getBody() {
return body;
}
void setBody(String body) {
this.body = body;
}
public String getRequestType() {
return requestType;
}
void setRequestType(String requestType) {
this.requestType = requestType;
}
public String getUrl() {
return parseUrl(this.url,this.paths);
}
void setUrl(String url) {
this.url = url;
}
LinkedList<KVEntry<String, String>> getPaths() {
return paths;
}
void addPath(KVEntry<String, String> KVEntry) {
if (paths==null){
paths = new LinkedList<>();
}
paths.add(KVEntry);
}
@Override
public String toString() {
return "MethodAnnotationInfo{" +
"requestType='" + requestType + '\'' +
", url='" + url + '\'' +
", headers=" + headers +
", params=" + params +
", body='" + body + '\'' +
'}';
}
/**
* 解析url--得到真正的url
*
* @return 解析后的url
*/
private String parseUrl(String url,LinkedList<KVEntry<String, String>> paths) {
if (paths != null && paths.size() > 0 && url.contains("{") && url.contains("}")) {
return checkUrl(url, paths);
} else {
return url;
}
}
/**
* 检查设置的url中是否还存在@Path中设置的路径
* @param newUrl 原url
* @param parameterEntries @Path中设置的路径
* @return 返回实际的url
*/
private String checkUrl(String newUrl, LinkedList<KVEntry<String, String>> parameterEntries) {
if (parameterEntries.size() <= 0) {
return newUrl;
}
KVEntry<String, String> KVEntry = parameterEntries.removeLast();
String key = KVEntry.getKey();
if (newUrl.contains(key)) {
String replace = newUrl.replace("{" + key + "}", KVEntry.getValue());
return checkUrl(replace, parameterEntries);
}
return newUrl;
}
}
看网络请求接口返回结果集的包装类:Call类
/**
* 接口返回值的包装类(也是真正执行类)
* @param <R>
*/
public class Call<R> {
private LQHttpAdapter lqHttpAdapter;
private MethodAnnotationInfo methodAnnotationInfo;
Call(LQHttpAdapter lqHttpAdapter, MethodAnnotationInfo methodAnnotationInfo) {
this.lqHttpAdapter = lqHttpAdapter;
this.methodAnnotationInfo = methodAnnotationInfo;
}
public void execute(CallBack<R> callBack) {
lqHttpAdapter.httpRequest(methodAnnotationInfo, callBack);
}
}
看LQHttpAdapter接口类:
/**
* 网络框架适配器 用于集成其它网络框架
*/
public interface LQHttpAdapter {
void httpRequest(MethodAnnotationInfo annotationInfo,CallBack callBack);
}
看CallBack类:
/**
* 执行的网络请求后的回调
* @param <R>
*/
public abstract class CallBack<R> {
public abstract void success(R r);
public abstract void fail(String e);
/**
* 进度回调
*
* @param progress
* @param total
*/
public void onProgress(int progress, long total) {
}
}
以上基本就是LqRetrofit实现的一些核心类;
最后就上一篇演示的测试demo中的OkHttpAdapter类,也就是如何去集成或自定义扩展:
/**
* 集成LQRetrofit的适配器:对OkHttp网络框架的适配器 的demo
*/
public class OkHttpAdapter implements LQHttpAdapter {
private static final OkHttpClient okHttpClient;
private static final Gson gson;
static {
okHttpClient = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build();
gson = new Gson();
}
@Override
public void httpRequest(MethodAnnotationInfo annotationInfo, CallBack callBack) {
Request.Builder builder = new Request.Builder().url(annotationInfo.getUrl());
switch (annotationInfo.getRequestType()) {
case RequestType.GET:
Map<String, String> headers = annotationInfo.getHeaders();
builder.get();
if (headers != null && headers.size() > 0) {
builder.headers(Headers.of(headers));
}
executeCallback(builder.build(), callBack, annotationInfo);
break;
case RequestType.POST:
//执行了okhttp的post请求...........
Request request = null;
FormBody.Builder formBodyBuilder = new FormBody.Builder();
Map<String, String> params = annotationInfo.getParams();
String body = annotationInfo.getBody();
if (params != null && body != null && body.length() > 0) {
throw new IllegalStateException("params and body can only exist one");
}
if (params != null && params.size() > 0) {
params.forEach(formBodyBuilder::add);
request = builder.post(formBodyBuilder.build()).build();
}
if (body != null && body.length() > 0) {
request = builder.post(RequestBody.create(MediaType.parse("application/json"), body)).build();
}
if (request == null) {
throw new IllegalStateException("params and body must specify one");
}
executeCallback(request, callBack, annotationInfo);
break;
case RequestType.PUT:
//执行了okhttp的put请求...........
break;
case RequestType.DELETE:
//执行了okhttp的delete请求...........
break;
case RequestType.PATCH:
//执行了okhttp的patch请求...........
break;
case RequestType.HEAD:
//执行了okhttp的head请求...........
break;
case RequestType.OPTIONS:
//执行了okhttp的options请求...........
break;
default:
break;
}
}
private void executeCallback(Request request, CallBack callBack, MethodAnnotationInfo annotationInfo) {
okHttpClient.newCall(request)
.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
callBack.fail(e.toString());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
ResponseBody body = response.body();
if (body != null) {
String json = body.string();
callBack.success(gson.fromJson(json, annotationInfo.getResultType()));
body.close();
} else {
callBack.fail("body is null");
}
}
});
}
}
所有代码已上传到了gitLib,可以根据代码中的注释去理解