日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Retrofit2.5是如何解析在接口类中定义的请求方法?

發(fā)布時間:2024/4/14 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Retrofit2.5是如何解析在接口类中定义的请求方法? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

Retrofit的核心在于它的create方法中使用了動態(tài)代理,在這里面主要是loadServiceMethod方法:

以下代碼基于Retrofit2.5.0(跟2.3.0代碼存在明顯不同)

public <T> T create(final Class<T> service) {//省略無關代碼return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },new InvocationHandler() {private final Platform platform = Platform.get();private final Object[] emptyArgs = new Object[0];@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)throws Throwable {//省略無關代碼return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);}});} 復制代碼

請求方法的解析

首先來看loadServiceMethod方法:

Retrofit.loadServiceMethod(Method method)

private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();ServiceMethod<?> loadServiceMethod(Method method) {ServiceMethod<?> result = serviceMethodCache.get(method);if (result != null) return result;synchronized (serviceMethodCache) {result = serviceMethodCache.get(method);if (result == null) {result = ServiceMethod.parseAnnotations(this, method);//解析方法serviceMethodCache.put(method, result);}}return result;} 復制代碼

serviceMethodCache是一個緩存的Map,這個方法主要就是執(zhí)行了ServiceMethod.parseAnnotations

先看看返回的類ServiceMethod

這個方法返回ServiceMethod這個類:

abstract class ServiceMethod<T> {//抽象類static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {//解析注解RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);//請求工廠初始化Type returnType = method.getGenericReturnType();//獲取方法的返回類型//省略無關代碼return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);//返回解析結果}abstract T invoke(Object[] args); } 復制代碼

繼續(xù)看RequestFactory.parseAnnotations(retrofit, method)

static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {return new Builder(retrofit, method).build();} 復制代碼

在這里又用到了創(chuàng)建者方法來創(chuàng)建這個請求工廠,進入Builder:

Builder(Retrofit retrofit, Method method) {this.retrofit = retrofit;//當前的retrofit實例this.method = method;//請求的方法this.methodAnnotations = method.getAnnotations();//注解this.parameterTypes = method.getGenericParameterTypes();//參數的類型集合this.parameterAnnotationsArray = method.getParameterAnnotations();//參數的注解集合} 復制代碼

可以看到這個創(chuàng)建類里面包含了我們在接口定義的方法的所有信息,包括注解和參數,再繼續(xù)來看它的build方法做了什么:

RequestFactory build() {for (Annotation annotation : methodAnnotations) {parseMethodAnnotation(annotation);//重點1.解析方法上面的注解}//省略無關代碼int parameterCount = parameterAnnotationsArray.length;parameterHandlers = new ParameterHandler<?>[parameterCount];for (int p = 0; p < parameterCount; p++) {parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]);//重點2.解析方法的參數}//省略無關代碼return new RequestFactory(this);} 復制代碼

在這里,進行了對方法的具體解析,主要是兩個步驟

  • 解析方法上面的注解parseMethodAnnotation
  • 解析方法的請求參數注解parseParameter
  • 到兩個方法里面看看:

    方法上面的注解

    RequestFactory.parseMethodAnnotation

    private void parseMethodAnnotation(Annotation annotation) {if (annotation instanceof DELETE) {parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);} else if (annotation instanceof GET) {parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);} else if (annotation instanceof HEAD) {parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);} else if (annotation instanceof PATCH) {parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);} else if (annotation instanceof POST) {parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);} else if (annotation instanceof PUT) {parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);} else if (annotation instanceof OPTIONS) {parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);} else if (annotation instanceof HTTP) {HTTP http = (HTTP) annotation;parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());} else if (annotation instanceof retrofit2.http.Headers) {String[] headersToParse = ((retrofit2.http.Headers) annotation).value();if (headersToParse.length == 0) {throw methodError(method, "@Headers annotation is empty.");}headers = parseHeaders(headersToParse);} else if (annotation instanceof Multipart) {if (isFormEncoded) {throw methodError(method, "Only one encoding annotation is allowed.");}isMultipart = true;} else if (annotation instanceof FormUrlEncoded) {if (isMultipart) {throw methodError(method, "Only one encoding annotation is allowed.");}isFormEncoded = true;}} 復制代碼

    在這里,看到了熟悉的一幕,我們平常使用Retrofit時在方法上面使用的@POST和@GET之類的注解,就是在這個方法里面進行的解析,這里先做一個判斷,繼續(xù)調用parseHttpMethodAndPath

    RequestFactory.parseHttpMethodAndPath

    private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {if (this.httpMethod != null) {throw methodError(method, "Only one HTTP method is allowed. Found: %s and %s.",this.httpMethod, httpMethod);}this.httpMethod = httpMethod;//請求方法this.hasBody = hasBody;//是否有請求體if (value.isEmpty()) {return;}// Get the relative URL path and existing query string, if present.int question = value.indexOf('?');if (question != -1 && question < value.length() - 1) {// Ensure the query string does not have any named parameters.String queryParams = value.substring(question + 1);Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);if (queryParamMatcher.find()) {throw methodError(method, "URL query string \"%s\" must not have replace block. "+ "For dynamic query parameters use @Query.", queryParams);}}this.relativeUrl = value;//相對請求地址this.relativeUrlParamNames = parsePathParameters(value);//解析請求鏈接里面的參數} 復制代碼

    在這里進行了關于請求的方法等相關屬性的賦值,最后調用parsePathParameters解析我們在注解里面?zhèn)魅氲牡刂返膮?#xff1a;

    RequestFactory.parsePathParameters

    private static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";private static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");static Set<String> parsePathParameters(String path) {Matcher m = PARAM_URL_REGEX.matcher(path);Set<String> patterns = new LinkedHashSet<>();while (m.find()) {patterns.add(m.group(1));}return patterns;} 復制代碼

    這里應該都能看懂,使用正則表達式來匹配。

    到這里,完成了對方法上面的注解的解析,接下來,進行對方法的參數的解析:

    方法的請求參數注解

    RequestFactory.parseParameter

    private ParameterHandler<?> parseParameter(int p, Type parameterType, @Nullable Annotation[] annotations) {ParameterHandler<?> result = null;if (annotations != null) {for (Annotation annotation : annotations) {ParameterHandler<?> annotationAction =parseParameterAnnotation(p, parameterType, annotations, annotation);//參數解析//省略無關代碼result = annotationAction;}}//省略無關代碼return result;} 復制代碼

    返回的ParameterHandler類為參數的句柄,這里是一個抽象類,里面有HeaderPathQuery等跟我們在參數前面加的標注同名的實現類。

    使用一個循環(huán),來解析每個參數的注解,這里調用了parseParameterAnnotation方法,這個方法跟剛才解析方法上面的注解parseMethodAnnotation很像,里面進行了很多判斷,在參數里面可以加的注解很多,所以方法太長,這里看一看我們經常用到的GET請求的@Query注解的解析:

    RequestFactory.parseParameterAnnotation

    //省略無關代碼} else if (annotation instanceof Query) {validateResolvableType(p, type);Query query = (Query) annotation;String name = query.value();boolean encoded = query.encoded();Class<?> rawParameterType = Utils.getRawType(type);//獲取類型gotQuery = true;if (Iterable.class.isAssignableFrom(rawParameterType)) {//是否是集合if (!(type instanceof ParameterizedType)) {throw parameterError(method, p, rawParameterType.getSimpleName()+ " must include generic type (e.g., "+ rawParameterType.getSimpleName()+ "<String>)");}ParameterizedType parameterizedType = (ParameterizedType) type;Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);Converter<?, String> converter =retrofit.stringConverter(iterableType, annotations);return new ParameterHandler.Query<>(name, converter, encoded).iterable();} else if (rawParameterType.isArray()) {//是否是集合的數組Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());Converter<?, String> converter =retrofit.stringConverter(arrayComponentType, annotations);return new ParameterHandler.Query<>(name, converter, encoded).array();} else {//普通類型Converter<?, String> converter =retrofit.stringConverter(type, annotations);return new ParameterHandler.Query<>(name, converter, encoded);}} else if (annotation instanceof QueryName) {//省略無關代碼 復制代碼

    在這個方法里面進行了類型和泛型相關的判斷,里面都調用了retrofit.stringConverter方法:

    retrofit.stringConverter

    public <T> Converter<T, String> stringConverter(Type type, Annotation[] annotations) {checkNotNull(type, "type == null");checkNotNull(annotations, "annotations == null");for (int i = 0, count = converterFactories.size(); i < count; i++) {Converter<?, String> converter =converterFactories.get(i).stringConverter(type, annotations, this);if (converter != null) {//noinspection uncheckedreturn (Converter<T, String>) converter;}}// Nothing matched. Resort to default converter which just calls toString().//noinspection uncheckedreturn (Converter<T, String>) BuiltInConverters.ToStringConverter.INSTANCE;} 復制代碼

    這個方法的作用是獲取請求參數的json解析器,一個循環(huán)從converterFactories數組中依次獲取加入的解析器工廠,我們在之前創(chuàng)建Retrofit傳入的是GsonConverterFactory,打開這個類,并沒有發(fā)現stringConverter方法,再打開它的父類Converter.Factory,看到了這個方法:

    public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,Retrofit retrofit) {return null;} 復制代碼

    返回的是空,說明這里不需要使用解析工廠將請求的參數轉化為String。所以直接調用最后一句

    return (Converter<T, String>) BuiltInConverters.ToStringConverter.INSTANCE; 復制代碼 static final class ToStringConverter implements Converter<Object, String> {static final ToStringConverter INSTANCE = new ToStringConverter();@Override public String convert(Object value) {return value.toString();}} 復制代碼

    返回的是一個默認的轉化類,在這個類的convert方法使用的是類自身的toString來轉化。

    到此為止,就完成了我們在接口中定義的那個方法的全部解析。

    總結

    Retrofit使用了動態(tài)代理,所以每次執(zhí)行我們在接口中定義的方法會來到動態(tài)代理中的invoke方法,在這里面,又執(zhí)行了loadServiceMethod來實現對方法的解析,主要是兩個步驟:

    • 解析方法上面的注解(如@Headers,@POST,@GET)
    • 解析方法的請求參數前面的注解(如@Query, @Field)

    總結

    以上是生活随笔為你收集整理的Retrofit2.5是如何解析在接口类中定义的请求方法?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。