private final Map<Method, ServiceMethod> serviceMethodCache = new ConcurrentHashMap<>();
public T create(final Class service) {
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service},
new InvocationHandler() {
@Override
public Object invoke(Object object, Method method, Object[] args) throws Throwable {
ServiceMethod serviceMethod = loadServiceMethod(method);
return serviceMethod.invoke(args);
}
});
}
/**
-
DLC 方式获取 ServiceMethod,如果没有解析过就解析该方法
-
@param method 动态代理执行的接口方法
-
@return 解析后的方法对象
*/
private ServiceMethod loadServiceMethod(Method method) {
// 先不加锁,避免性能损失
ServiceMethod serviceMethod = serviceMethodCache.get(method);
if (serviceMethod != null) return serviceMethod;
// 避免多线程下重复解析
synchronized (serviceMethodCache) {
serviceMethod = serviceMethodCache.get(method);
if (serviceMethod == null) {
serviceMethod = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, serviceMethod);
}
}
return serviceMethod;
}
在 ServiceMethod 的 Builder 中解析方法和参数注解:
public class ServiceMethod {
private final String httpMethod;
private final Call.Factory callFactory;
private final HttpUrl baseUrl;
private final String relativeUrl;
private final ParameterHandler[] parameterHandlers;
private FormBody.Builder formBuilder;
private FormBody formBody;
private HttpUrl.Builder urlBuilder;
public ServiceMethod(Builder builder) {
baseUrl = builder.retrofit.baseUrl;
callFactory = builder.retrofit.callFactory;
httpMethod = builder.httpMethod;
relativeUrl = builder.relativeUrl;
parameterHandlers = builder.parameterHandlers;
boolean hasBody = builder.hasBody;
// 如果有请求体,创建一个 OKHttp 请求体对象
if (hasBody) {
formBuilder = new FormBody.Builder();
}
}
static class Builder {
private final SimpleRetrofit retrofit;
private final Method method;
private final Annotation[] annotations;
// 方法上有 n 个参数,每个参数又有 m 个注解,用一个 nxm 的数组保存
private final Annotation[][] parameterAnnotations;
String httpMethod;
boolean hasBody;
String relativeUrl;
ParameterHandler[] parameterHandlers;
public Builder(SimpleRetrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
annotations = method.getAnnotations();
parameterAnnotations = method.getParameterAnnotations();
}
public ServiceMethod build() {
// 解析方法上的注解
for (Annotation annotation : annotations) {
if (annotation instanceof GET) {
parseHttpMethodAndPath(“GET”, ((GET) annotation).value(), false);
} else if (annotation instanceof POST) {
parseHttpMethodAndPath(“POST”, ((POST) annotation).value(), true);
}
}
// 解析方法参数上的所有注解,把注解值存入 ParameterHandler[] 中
int length = parameterAnnotations.length; // 方法上的参数个数
parameterHandlers = new ParameterHandler[length];
for (int i = 0; i < length; i++) {
// 一个参数上的所有注解
Annotation[] annotations = parameterAnnotations[i];
parameterHandlers[i] = parseParameter(annotations);
}
return new ServiceMethod(this);
}
private ParameterHandler parseParameter(Annotation[] annotations) {
// 根据注解类型创建对应的 ParameterHandler
ParameterHandler result = null;
for (Annotation annotation : annotations) {
ParameterHandler annotationAction = parseParameterAction(annotation, annotations);
// 如果当前检查的注解并不是我们能处理的,就继续遍历下一个
if (annotationAction == null) {
continue;
}
// 如果 result 不为 null 说明之前遍历时已经找到了 SimpleRetrofit 能处理的注解
// 不允许一个参数上被多个 SimpleRetrofit 的参数注解标注,抛异常
if (result != null) {
throw new IllegalArgumentException(“Multiple Retrofit annotations found, only one allowed.”);
}
result = annotationAction;
}
// 遍历完都没找到说明这个参数没有被 SimpleRetrofit 注解标注,不应该被检查
if (result == null) {
throw new IllegalArgumentException(“No Retrofit annotation found.”);
}
return result;
}
private ParameterHandler parseParameterAction(Annotation annotation, Annotation[] annotations) {
if (annotation instanceof Query) {
String key = ((Query) annotation).value();
return new ParameterHandler.QueryParameterHandler(key);
} else if (annotation instanceof Field) {
String key = ((Field) annotation).value();
return new ParameterHandler.FieldParameterHandler(key);
}
return null;
}
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
// 规定一个方法上只能有一个 httpMethod 注解,否则抛出异常
if (this.httpMethod != null) {
String message = String.format(“Only one HTTP method is allowed. Found: %s and %s.”,
this.httpMethod, httpMethod);
throw new IllegalArgumentException(message);
}
this.httpMethod = httpMethod;
this.hasBody = hasBody;
if (value == null) {
return;
}
this.relativeUrl = value;
}
}
}
build() 中负责解析方法注解和方法参数注解。解析方法注解主要是为了获取使用哪种 HTTP 方法(GET、POST)、是否有请求体以及相对地址;解析方法参数注解是为了把被 @Field 或 @Query 注解的参数的值,即网络请求的 key 保存在 ParameterHandler[] 中。比如说对于 getWeather():
@GET(“/v3/weather/weatherInfo”)
Call getWeather(@Query(“city”) String city, @Query(“key”) String key);
@Query 注解的值分别为 city、key,那么就把 city 和 key 分别传入 ParameterHandler[] 中保存,而这两个 key 对应的 value 会在调用 ServiceMethod 的 invoke() 方法时传入。
ParameterHandler 的作用是保存网络请求的 key,并把 key-value 回调给 ServiceMethod:
public abstract class ParameterHandler {
abstract void apply(ServiceMethod serviceMethod, String value);
static class QueryParameterHandler extends ParameterHandler {
String key;
public QueryParameterHandler(String key) {
this.key = key;
}
@Override
void apply(ServiceMethod serviceMethod, String value) {
serviceMethod.addQueryParameter(key, value);
}
}
static class FieldParameterHandler extends ParameterHandler {
String key;
public FieldParameterHandler(String key) {
this.key = key;
}
@Override
void apply(ServiceMethod serviceMethod, String value) {
serviceMethod.addFieldParameter(key, value);
}
}
}
回调方法一个是处理 GET 请求的,一个是处理 POST 请求的:
// get 请求,把 key-value 拼接到 url 中
public void addQueryParameter(String key, String value) {
if (urlBuilder == null) {
urlBuilder = baseUrl.newBuilder(relativeUrl);
}
urlBuilder.addQueryParameter(key, value);
}
// post 请求,把 key-value 放到请求体中
public void addFieldParameter(String key, String value) {
formBuilder.add(key, value);
}
最后在 invoke() 中生成 OKHttp 的 Request 对象并调用 CallFactory 的 newCall(Request) 生成 Call:
public Object invoke(Object[] args) {
for (int i = 0; i < parameterHandlers.length; i++) {
ParameterHandler parameterHandler = parameterHandlers[i];
parameterHandler.apply(this, args[i].toString());
}
if (urlBuilder == null) {
urlBuilder = baseUrl.newBuilder(relativeUrl);
}
HttpUrl httpUrl = urlBuilder.build();
if (formBuilder != null) {
formBody = formBuilder.build();
}
Request request = new Request.Builder().url(httpUrl).method(httpMethod, formBody).build();
return callFactory.newCall(request);
}
2、使用
====
注解见上,不重复写了。
2.1、SimpleRetrofit
package com.test.retrofittest2.retro;
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 SimpleRetrofit {
HttpUrl baseUrl;
Call.Factory callFactory;
private final Map<Method, ServiceMethod> serviceMethodCache = new ConcurrentHashMap<>();
public SimpleRetrofit(Builder builder) {
this.baseUrl = builder.baseUrl;
this.callFactory = builder.callFactory;
}
public static class Builder {
HttpUrl baseUrl;
Call.Factory callFactory;
public Builder baseUrl(String baseUrl) {
this.baseUrl = HttpUrl.parse(baseUrl);
return this;
}
public SimpleRetrofit build() {
// 先做参数校验
if (baseUrl == null) {
throw new IllegalStateException(“Base URL required.”);
}
if (callFactory == null) {
callFactory = new OkHttpClient();
}
return new SimpleRetrofit(this);
}
}
@SuppressWarnings(“unchecked”)
public T create(final Class service) {
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service},
new InvocationHandler() {
@Override
public Object invoke(Object object, Method method, Object[] args) throws Throwable {
ServiceMethod serviceMethod = loadServiceMethod(method);
return serviceMethod.invoke(args);
}
});
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
最后
这里我希望可以帮助到大家提升进阶。
内容包含:Android学习PDF+架构视频+面试文档+源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。
喜欢本文的话,不妨给我点个小赞、评论区留言或者转发支持一下呗~
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
+架构视频+面试文档+源码笔记**,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。
喜欢本文的话,不妨给我点个小赞、评论区留言或者转发支持一下呗~
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算