首先經過Utils.validateServiceInterface(service);
來檢查傳入的參數是不是一個沒有繼承關係的接口,這是怎麼判斷的呢?java
static <T> void validateServiceInterface(Class<T> service) { if (!service.isInterface()) {//1.判斷是不是interface throw new IllegalArgumentException("API declarations must be interfaces."); } if (service.getInterfaces().length > 0) {//2.判斷是否實現了接口 throw new IllegalArgumentException("API interfaces must not extend other interfaces."); } }
而後eagerlyValidateMethods(service)是什麼鬼?正則表達式
private void eagerlyValidateMethods(Class<?> service) { Platform platform = Platform.get(); for (Method method : service.getDeclaredMethods()) { if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) { loadServiceMethod(method); } } }
其實這個方法中,主要是對service中的全部方法作了檢查,不容許存在靜態方法。數組
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; }
接下來就是把反射出來的方法緩存,其中緩存的方式是調用ServiceMethod.parseAnnotations(this, method);
把method轉換成RequestFactory
對象:緩存
final class RequestFactory { static RequestFactory parseAnnotations(Retrofit retrofit, Method method) { return new Builder(retrofit, method).build(); } ...
咱們看這裏的builder都幹了哪些勾當,首先看構造方法:網絡
Builder(Retrofit retrofit, Method method) { this.retrofit = retrofit; this.method = method; this.methodAnnotations = method.getAnnotations(); this.parameterTypes = method.getGenericParameterTypes(); this.parameterAnnotationsArray = method.getParameterAnnotations(); }
而後再看build()方法,乾的勾當更多:post
RequestFactory build() { for (Annotation annotation : methodAnnotations) { //判斷加了哪些註解,肯定網絡傳輸方式 parseMethodAnnotation(annotation); } if (httpMethod == null) { throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc.)."); } if (!hasBody) { if (isMultipart) { throw methodError(method, "Multipart can only be specified on HTTP methods with request body (e.g., @POST)."); } if (isFormEncoded) { throw methodError(method, "FormUrlEncoded can only be specified on HTTP methods with " + "request body (e.g., @POST)."); } } int parameterCount = parameterAnnotationsArray.length; parameterHandlers = new ParameterHandler<?>[parameterCount]; for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) { parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter); } if (relativeUrl == null && !gotUrl) { throw methodError(method, "Missing either @%s URL or @Url parameter.", httpMethod); } if (!isFormEncoded && !isMultipart && !hasBody && gotBody) { throw methodError(method, "Non-body HTTP method cannot contain @Body."); } if (isFormEncoded && !gotField) { throw methodError(method, "Form-encoded method must contain at least one @Field."); } if (isMultipart && !gotPart) { throw methodError(method, "Multipart method must contain at least one @Part."); } return new RequestFactory(this); }
/** * 這一步主要是用來判斷加了哪些註解 **/ 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; } }
/** * 肯定網絡傳輸方式,如get、post、delete * 而且提取出了真實的url和url中攜帶的參數名稱 **/ private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) { //檢測httpmethod,不容許加多個http方法註解 if (this.httpMethod != null) { throw methodError(method, "Only one HTTP method is allowed. Found: %s and %s.", this.httpMethod, httpMethod); } //肯定了網絡傳輸方法,好比get、post、delete等 this.httpMethod = httpMethod; this.hasBody = hasBody; if (value.isEmpty()) { return; } // Get the relative URL path and existing query string, if present. //這裏是用正則表達式作判斷,要求url中的參數必須用括號佔位 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); } } //獲取真實的url this.relativeUrl = value; //從url中攝取參數名稱 this.relativeUrlParamNames = parsePathParameters(value); }
看到這裏,我發現retrofit是支持HERDER請求的,固然,在if (annotation instanceof retrofit2.http.Headers)
部分的邏輯也是有區別的:ui
private Headers parseHeaders(String[] headers) { Headers.Builder builder = new Headers.Builder(); for (String header : headers) { int colon = header.indexOf(':'); if (colon == -1 || colon == 0 || colon == header.length() - 1) { throw methodError(method, "@Headers value must be in the form \"Name: Value\". Found: \"%s\"", header); } String headerName = header.substring(0, colon); String headerValue = header.substring(colon + 1).trim(); if ("Content-Type".equalsIgnoreCase(headerName)) { try { contentType = MediaType.get(headerValue); } catch (IllegalArgumentException e) { throw methodError(method, e, "Malformed content type: %s", headerValue); } } else { builder.add(headerName, headerValue); } } return builder.build(); }
而後繼續看build方法,通過了方法註解處理和一堆的驗證,而後到了參數處理部分:this
int parameterCount = parameterAnnotationsArray.length; parameterHandlers = new ParameterHandler<?>[parameterCount]; for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) { parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter); }
原來for循環還能這麼寫啊,老外就是會玩,parseParameter()的三個參數重的最後一個參數表示循環是否繼續,納尼,我沒看到break、continue和return啊老弟,你怎麼作到的?原來是在parseParameter()
方法中去判斷這個參數,若是爲false就直接throw了一個Exception!特麼靠異常去終結循環啊,神來之筆!url
其中的parseParameter
方法,就是對各類參數註解的處理。code