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