public @interface Get {
String value() default "" ;
}
@Target(METHOD )
@Retention(RUNTIME )
public @interface Get {
String value() default "" ;
}
我们简单解释1下这个注解的意思,这个注解表示注解用于在方法上,在运行时可见,如果要用到参数上,像下面:
@Target(PARAMETER )
@Retention(RUNTIME )
public @interface Path {
String value() default "" ;
}
更多就请看这个类了
java.lang.annotation.ElementType
/**
* Returns an instance of the dynamically built class for the specified
* interfaces. Method invocations on the returned instance are forwarded to
* the specified invocation handler. The interfaces must be visible from the
* supplied class loader; no duplicates are permitted. All non-public
* interfaces must be defined in the same package.
*
* @param loader
* the class loader that will define the proxy class
* @param interfaces
* an array of {@code Class} objects, each one identifying an
* interface that will be implemented by the returned proxy
* object
* @param invocationHandler
* the invocation handler that handles the dispatched method
* invocations
* @return a new proxy object that delegates to the handler {@code h}
* @throws IllegalArgumentException
* if any of the interface restrictions are violated
* @throws NullPointerException
* if the interfaces or any of its elements are null
*/
public static Object newProxyInstance (ClassLoader loader ,
Class<?>[] interfaces,
InvocationHandler h)
我们看这个方法上面的注释
返回指定接口的动态生成类的实例。在返回的实例方法调用被转发到InvocationHandler上面。必须从所提供的类装载器可见接口;不允许任何重复。所有非公共接口必须在同1个包中定义。
也许还是没有看懂,说白了就是通过给定的接口生成1个对应的实例,这个接口的方法在实例中实现的时候被反过来调用InvocationHandler上
- InvocationHandler
所以我们需要去实现InvocationHandler类
new InvocationHandler() {
@Override
public Object invoke(Object proxy , Method method, Object[] args ) throws Throwable {
return null;
}
}
很明显,你只要调用这个接口的方法,都会被反过来调用上面这个方法,
我们来看这个方法的参数
Object proxy
Method method 这个是接口方法的1些描写,里面包括对方法的各种描写。
Object[] args 就是你调用这个方式时,实际的参数。
所以整合起来,写个例子:
@Documented
@Target(METHOD )
@Retention(RUNTIME )
public @interface Get {
String value() default "" ;
}
@Documented
@Target(PARAMETER )
@Retention(RUNTIME )
public @interface Path {
String value() default "" ;
}
public interface IIterface {
@Get(value="testPath" )
String testMethod( @Path ("path" )String path);
}
public static void main(String[] args) {
IIterface test = (IIterface) Proxy.newProxyInstance(IIterface.class.getClassLoader(), new Class[] { IIterface.class },
new InvocationHandler() {
@Override
public Object invoke(Object proxy , Method method, Object[] args ) throws Throwable {
StringBuilder sb = new StringBuilder();
method.getReturnType();// return type.
Annotation[][] anss = method.getParameterAnnotations();
String pathValue = "" ;
out: for (Annotation[] ans : anss) {
for (Annotation an : ans) {
if(an instanceof Path){
Path path = (Path)an ;
pathValue = path.value();
break out;
}
}
}
Get get = method.getAnnotation(Get .class);
String value = get .value();
sb.append( value).append("/" );
sb.append( pathValue).append("/" );
sb.append( args[0]);
return sb .toString();
}
});
String result = test .testMethod("code_path");
System. out.println(result );
}
通过这个例子,应当可以完成理解注解的使用了吧。
如果想下载完成demo
通过上面的demo我们来看Retrofit2的代码就简单了。
我们在使用的时候不是先需要定义1个接口吗?
如:
public interface FusionApi {
@GET("/fusion/settings/v1/users/{userId}/applications")
Observable<List<CloudState>> applicationsRx(@Path("userId") String userId);
}
我们创建对应的实例:
public FusionApi createFusionApi(){
Retrofit.Builder builder = new Retrofit.Builder();
builder.baseUrl(base_url);
builder.addConverterFactory(GsonConverterFactory.create());
builder.addCallAdapterFactory(RxJavaCallAdapterFactory.create());
return builder.build().create(FusionApi.class);
}
然后我们在使用的时候:
@Test
public void applicationsRx() throws Exception {
FusionService.getFusionService().setClientInfo(clientInfo);
Observable<List<CloudState>> call = FusionService.getFusionService().setClientInfo(clientInfo).createFusionApi().applicationsRx(userId);
call.subscribe(new Action1<List<CloudState>>() {
@Override
public void call(List<CloudState> cloudStates) {
System.out.println(cloudStates);
}
});
}
固然这里使用了Observable了,下1篇我将会使用RxJava和Reconfic2的整合。
其实你看了这篇基本上都已全部使用到了,唯1少了点Observable的使用。
扯远来,回到我们的话题。
根据我们前面的代码,我们来看下create方法:
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
1行1行代码的来解释下:
第2行: 主要检测传入进来的参数是不是为interface接口
第3⑸行: 主要验证这service的方法
接下来就是我们前面看到 需要重点分析的代码:
private final Platform platform = Platform.get();
这1行,由于Recofict2支持3个平台,android ios java8 所以在这里选择平太,很明显我们是Android平台。
看下这个方法:
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
其实看这个方法很容易理解,1个就是先了1个线程池来履行,1个主线成应当运行的的地方。想必Android入门了,就很容易理解。
接下来看
@Override public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
很明显前面2个if都不成立,所以我们直接来看
ServiceMethod serviceMethod = loadServiceMethod(method);
下面我们来看看 这个loadServiceMethod方法做了甚么?
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
这个方法其实没干甚么,就是把method封装成ServiceMethod,做了1下缓存,如果有直接取,没有就重新封装1次,我们看看这个封装的方法:
result = new ServiceMethod.Builder(this, method).build();
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
第1个参数先不讲授,第2个参数先从里面读取这个方法所有的注解。
我们再看build方法:
public ServiceMethod build() {
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError("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; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
if (relativeUrl == null && !gotUrl) {
throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError("Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError("Multipart method must contain at least one @Part.");
}
return new ServiceMethod<>(this);
}
先不看retrofit这个的使用,这个后面讲授:
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
对方法的每一个注解进行解析,我们看具体怎样解析
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);
if (!Void.class.equals(responseType)) {
throw methodError("HEAD method must use Void as response type.");
}
} 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("@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError("Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError("Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
其实很简单,就是对这个注解1个1个进行判断,是不是是我们已定义的注解类型。然后做了检查而已,然后标注哪些注解将被用到。
我们读其中1个注解的解析:
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
if (this.httpMethod != null) {
throw methodError("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("URL query string \"%s\" must not have replace block. "
+ "For dynamic query parameters use @Query.", queryParams);
}
}
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);
}
这个方法是读取里面的具体参数的值,然后存入到relativeUrl,relativeUrlParamNames 这里面,
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;
}
然后我们回到开始:
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
这句代码,我们上面已解释了ServiceMethod这个里面有啥了。
args 是这个方法传入具体的参数值
然后看这句:
public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
}
从这里就是取出adapter
那我们看看这adapter里面存的是甚么,然后有得到的是甚么样的callAdapter
搜素源码能看到 就是我们构造build的时候,使用这个方法添加进去的
addCallAdapterFactory我这里是 用的RxJava
固然没有添加的话,使用的是系统默许的。至于甚么时候选择哪一个,你看上面的方法就知道了,通过注解和返回类型匹配的话,就选择哪一个,如果我们返回的不是Observer类型,那我们应当是Reforcit默许的,我们看看默许的是啥?
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
if (callbackExecutor != null) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapterFactory.INSTANCE;
}
通过判断,我们没有实例callbackExecutor,应当是
所以应当是这个:
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
既然找到他的实例了,我们来看看adapt 方法:
@Override
public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public <R> Call<R> adapt(Call<R> call) {
return call;
}
};
}
事实也是如此。
我们传入的参数 是OkHttpCall
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
所以返回的是OkHttpCall ,是否是感觉转了1圈,回到出发点,啥也没干嘛?
如果那样理解那就错了。
在这里,你外面不是使用的是Call的返回参数,所以这个时候,你调用
call.execute().body(); 就得到最后的答案了吗?
所以我们跟进这个OkHttpCall来看下。
@Override
public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
if (creationFailure != null) {
if (creationFailure instanceof IOException) {
throw (IOException) creationFailure;
} else {
throw (RuntimeException) creationFailure;
}
}
call = rawCall;
if (call == null) {
try {
call = rawCall = createRawCall();
} catch (IOException | RuntimeException e) {
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
return parseResponse(call.execute());
}
看上面的代码,重要的是2行代码,
1行是:call = rawCall = createRawCall();
那我们先看看这个方法:
createRawCall
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
第1行:我们看方法:
Request toRequest(Object... args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.build();
}
Request build() {
HttpUrl url;
HttpUrl.Builder urlBuilder = this.urlBuilder;
if (urlBuilder != null) {
url = urlBuilder.build();
} else {
// No query parameters triggered builder creation, just combine the relative URL and base URL.
url = baseUrl.resolve(relativeUrl);
if (url == null) {
throw new IllegalArgumentException(
"Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl);
}
}
RequestBody body = this.body;
if (body == null) {
// Try to pull from one of the builders.
if (formBuilder != null) {
body = formBuilder.build();
} else if (multipartBuilder != null) {
body = multipartBuilder.build();
} else if (hasBody) {
// Body is absent, make an empty body.
body = RequestBody.create(null, new byte[0]);
}
}
MediaType contentType = this.contentType;
if (contentType != null) {
if (body != null) {
body = new ContentTypeOverridingRequestBody(body, contentType);
} else {
requestBuilder.addHeader("Content-Type", contentType.toString());
}
}
return requestBuilder
.url(url)
.method(method, body)
.build();
是在这里根据参数,注解,构造了1个http要求吗?这里面就有了全部http要求的消息了。
回到原来的那个地方,我们分析第2个,如果对okhttp比较熟习的话,这就可以直接看懂了,但是我还是1直分析下去。
前面1行代码分析完了,我们来分析第2处:
parseResponse(call.execute());
call.execute(),就是根据上面全部http要求,得到了http的返回,然后再进行分析,我们来看分析的代码:
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// Remove the body's source (the only stateful object) so we can pass the response along.
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
if (code < 200 || code >= 300) {
try {
// Buffer the entire body to avoid future I/O.
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) {
return Response.success(null, rawResponse);
}
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
如果要求时成功的,则我们只需要看着两行代码:
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
跟入到这行代码
T toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
1看就知道,经过1个Converter,转换到我们想要的类型了。所以body就是我们要的封装结果。
然后以封装最后的数据类型传回了我们最初的调用端。
这里走分析源码已走了1圈了。
文章写的乱,第1次写,可能思路写的不是很清晰,后续可以需要修改。
上一篇 超级表格表单设计全新起航
下一篇 WAN接入/互联配置与管理——2