首先经过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