public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
//platform.defaultCallbackExecutor()返回的是MainThreadExecutor
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
//platform.defaultCallAdapterFactories()在SDK版本大于等于24的时候
//返回集合[CompletableFutureCallAdapterFactory,DefaultCallAdapterFactory]
//否则返回集合[DefaultCallAdapterFactory]
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// Make a defensive copy of the converters.
List converterFactories = new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
//内置BuiltInConverters,排在最前的符合要求converter会先用到,方式用户定义了一个一模一样的convert
converterFactories.add(new BuiltInConverters());
//用户配置的自定义Converter
converterFactories.addAll(this.converterFactories);
//platform.defaultConverterFactories()在SDK版本大于等于24返回OptionalConverterFactory,主要是针对java8的Optional否则返回空
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
可以看到就是配置参数给Retrofit构造函数传值,下面进入代理对象创建环节。
创建接口的代理对象
注:例子引用了 samples
//实体类定义
public static class Contributor {
public final String login;
public final int contributions;
public Contributor(String login, int contributions) {
this.login = login;
this.contributions = contributions;
}
}
//接口定义
public interface GitHub {
@GET("/repos/{owner}/{repo}/contributors")
Call> contributors(
@Path("owner") String owner,
@Path("repo") String repo);
}
//关键点,创建代理对象
GitHub github = retrofit.create(GitHub.class);
//调用代理对象方法,如果没有在Retrofit的builder方法中配置
//.addCallAdapterFactory(RxJava2CallAdapterFactory.create())则返回的是Call
Call> call = github.contributors("square", "retrofit");
// 网络请求返回数据
List contributors = call.execute().body();
for (Contributor contributor : contributors) {
System.out.println(contributor.login + " (" + contributor.contributions + ")");
}
package retrofit2;
public final class Retrofit {
public T create(final Class service) {
//校验service类格式,service必须是接口类型,并且不能继承自其他接口
Utils.validateServiceInterface(service);
//Retrofit的builder类的validateEagerly方法配置,默认为false
if (validateEagerly) {
//主要是校验service类中所申明的方法不能是default方法(java 8中interface引入了default方法)
//同时不能是静态方法,如果满足要求,则调用loadServiceMethod方法
eagerlyValidateMethods(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 @Nullable Object invoke(Object proxy, Method method,
@Nullable Object[] args) throws Throwable {
// If the method is a method from Object then defer to normal invocation.
//如果是调用的继承自Object方法(比如toString();hashCode(),wait(),notify,getClass())则普通调用,
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//如果是java8的默认方法
if (platform.isDefaultMethod(method)) {
//调用invokeDefaultMethod,实际实现是抛出UnsupportedOperationException异常
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//核心代码,API接口申明的那些方法
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
}
package retrofit2;
final class RequestFactory {
//省略其他代码
RequestFactory build() {
//遍历修饰方法的注解,只解析Retrofit支持的那几个注解
for (Annotation annotation : methodAnnotations) {
//解析方法上的HTTP注解 ,后面分析
parseMethodAnnotation(annotation);
}
//没有找到Retrofit支持的那几个用于HTTP请求的注解,抛出异常
if (httpMethod == null) {
throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
//如果不带请求体,只有PATCH,POST,PUT方法才带有请求体,说明不能在方法上用了@DELETE,@HEAD,@GET,@OPTIONS注解后又用@Multipart,@FormUrlEncoded注解
//具体规范参考HTTP协议
//hasBody,isMultipart,isFormEncoded的判断在上面的parseMethodAnnotation中完成
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).");
}
}
//针对带有注解的参数,创建对应的参数处理器ParameterHandler
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);
}
//relativeUrl ,gotUrl,gotField,gotPart的判断在parseParameter方法中完成
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 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();
}
接着分析 parseParameter( int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation)方法:
private @Nullable ParameterHandler parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
ParameterHandler result = null;
if (annotations != null) {
for (Annotation annotation : annotations) {
//通过parseParameterAnnotation来获取对应的ParameterHandler
ParameterHandler annotationAction =
parseParameterAnnotation(p, parameterType, annotations, annotation);
if (annotationAction == null) {
continue;
}
if (result != null) {
throw parameterError(method, p,
"Multiple Retrofit annotations found, only one allowed.");
}
result = annotationAction;
}
}
if (result == null) {
//当为最后一个参数的时候allowContinuation为true
if (allowContinuation) {
try {
//Continuation.class是Kotlin协程模块中kotlin.coroutines.Continuation;
//有关协程请参考https://kotlinlang.org/docs/reference/coroutines/coroutines-guide.html
if (Utils.getRawType(parameterType) == Continuation.class) {
isKotlinSuspendFunction = true;
return null;
}
} catch (NoClassDefFoundError ignored) {
}
}
throw parameterError(method, p, "No Retrofit annotation found.");
}
return result;
}
实际上还是调用的是ParameterHandler parseParameterAnnotation( int p, Type type, Annotation[] annotations, Annotation annotation)方法。由于这个方法比较长,但是做的事情还是很清楚的,就是根据api接口中申明的参数注解类型生成相应的ParameterHandler,同时参数不能为不可解析类型,就是前文的hasUnresolvableType(@Nullable Type type)的逻辑。未落不冲谈主题且限于篇幅,此处只是列出该方法的几个最外层的条件分支,根据不同的注解@Url,@Path,@Query,@QueryName,@QueryMap,@Header,@HeaderMap,@Feild,@FieldMap,@Part,@PartMap,@Body,@Tag,生成相应的ParameterHandler。
private ParameterHandler parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
if (annotation instanceof Url) { //如果是@Url注解,返回ParameterHandler.RelativeUrl
//省略一堆逻辑
。。。
if (type == HttpUrl.class
|| type == String.class
|| type == URI.class
|| (type instanceof Class && "android.net.Uri".equals(((Class) type).getName()))) {
return new ParameterHandler.RelativeUrl(method, p);
} else {
throw parameterError(method, p,
"@Url must be okhttp3.HttpUrl, String, java.net.URI, or android.net.Uri type.");
}
} else if (annotation instanceof Path) { //如果是@Path注解,返回ParameterHandler.Path
//省略一堆逻辑
。。。
Converter converter = retrofit.stringConverter(type, annotations);
return new ParameterHandler.Path<>(method, p, name, converter, path.encoded());
} else if (annotation instanceof Query) { //如果是@Query注解,返回ParameterHandler.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()
+ ")");
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter converter =
retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.Query<>(name, converter, encoded).iterable();
} else if (rawParameterType.isArray()) {
Class arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Query<>(name, converter, encoded).array();
} else {
Converter converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.Query<>(name, converter, encoded);
}
} else if (annotation instanceof QueryName) {//如果是@QueryName 注解,返回ParameterHandler.QueryName
validateResolvableType(p, type);
QueryName query = (QueryName) annotation;
boolean encoded = query.encoded();
Class rawParameterType = Utils.getRawType(type);
gotQueryName = true;
if (Iterable.class.isAssignableFrom(rawParameterType)) {
if (!(type instanceof ParameterizedType)) {
throw parameterError(method, p, rawParameterType.getSimpleName()
+ " must include generic type (e.g., "
+ rawParameterType.getSimpleName()
+ ")");
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter converter =
retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.QueryName<>(converter, encoded).iterable();
} else if (rawParameterType.isArray()) {
Class arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.QueryName<>(converter, encoded).array();
} else {
Converter converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.QueryName<>(converter, encoded);
}
} else if (annotation instanceof QueryMap) { //如果是@QueryMap 注解,返回ParameterHandler.QueryMap
//省略一堆逻辑
。。。。
return new ParameterHandler.QueryMap<>(method, p,
valueConverter, ((QueryMap) annotation).encoded());
} else if (annotation instanceof Header) { //如果是@Header 注解,返回ParameterHandler.Header
validateResolvableType(p, type);
Header header = (Header) annotation;
String name = header.value();
Class rawParameterType = Utils.getRawType(type);
if (Iterable.class.isAssignableFrom(rawParameterType)) {
if (!(type instanceof ParameterizedType)) {
throw parameterError(method, p, rawParameterType.getSimpleName()
+ " must include generic type (e.g., "
+ rawParameterType.getSimpleName()
+ ")");
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter converter =
retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.Header<>(name, converter).iterable();
} else if (rawParameterType.isArray()) {
Class arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Header<>(name, converter).array();
} else {
Converter converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.Header<>(name, converter);
}
} else if (annotation instanceof HeaderMap) {//如果是@HeaderMap 注解,返回ParameterHandler.Headers或者ParameterHandler.HeaderMap
if (type == Headers.class) {
return new ParameterHandler.Headers(method, p);//返回ParameterHandler.Headers
}
//省略一堆逻辑
。。。。
return new ParameterHandler.HeaderMap<>(method, p, valueConverter); //返回ParameterHandler.HeaderMap
} else if (annotation instanceof Field) {//如果是@Field 注解,返回ParameterHandler.Field
//省略一堆逻辑
。。。。
Class rawParameterType = Utils.getRawType(type);
if (Iterable.class.isAssignableFrom(rawParameterType)) {
//省略一堆逻辑
。。。。
return new ParameterHandler.Field<>(name, converter, encoded).iterable();
} else if (rawParameterType.isArray()) {
//省略一堆逻辑
。。。。
return new ParameterHandler.Field<>(name, converter, encoded).array();
} else {
//省略一堆逻辑
。。。。
return new ParameterHandler.Field<>(name, converter, encoded);
}
} else if (annotation instanceof FieldMap) { //如果是@FieldMap 注解,返回ParameterHandler.Field
//省略一堆逻辑
。。。。
return new ParameterHandler.FieldMap<>(method, p,
valueConverter, ((FieldMap) annotation).encoded());
} else if (annotation instanceof Part) { //如果是@Part 注解,根据具体情况返回ParameterHandler.RawPart或者ParameterHandler.Part
validateResolvableType(p, type);
if (!isMultipart) {
throw parameterError(method, p,
"@Part parameters can only be used with multipart encoding.");
}
Part part = (Part) annotation;
gotPart = true;
String partName = part.value();
Class rawParameterType = Utils.getRawType(type);
if (partName.isEmpty()) {
if (Iterable.class.isAssignableFrom(rawParameterType)) {
//省略一堆逻辑
。。。
return ParameterHandler.RawPart.INSTANCE.iterable();
} else if (rawParameterType.isArray()) {
//省略一堆逻辑
。。。
return ParameterHandler.RawPart.INSTANCE.array();
} else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
return ParameterHandler.RawPart.INSTANCE;
} else {
throw parameterError(method, p,
"@Part annotation must supply a name or use MultipartBody.Part parameter type.");
}
} else {
Headers headers =
Headers.of("Content-Disposition", "form-data; name=\"" + partName + "\"",
"Content-Transfer-Encoding", part.encoding());
if (Iterable.class.isAssignableFrom(rawParameterType)) {
//省略一堆逻辑
。。。
return new ParameterHandler.Part<>(method, p, headers, converter).iterable();
} else if (rawParameterType.isArray()) {
//省略一堆逻辑
。。。
return new ParameterHandler.Part<>(method, p, headers, converter).array();
} else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
throw parameterError(method, p,
"@Part parameters using the MultipartBody.Part must not "
+ "include a part name in the annotation.");
} else {
Converter converter =
retrofit.requestBodyConverter(type, annotations, methodAnnotations);
return new ParameterHandler.Part<>(method, p, headers, converter);
}
}
} else if (annotation instanceof PartMap) { //如果是@PartMap 注解,返回ParameterHandler.PartMap
//省略一堆逻辑
。。。。
return new ParameterHandler.PartMap<>(method, p, valueConverter, partMap.encoding());
} else if (annotation instanceof Body) { //如果是@Body 注解,返回ParameterHandler.Body
//省略一堆逻辑
。。。。
return new ParameterHandler.Body<>(method, p, converter);
} else if (annotation instanceof Tag) { //如果是@Tag 注解,返回ParameterHandler.Tag
//省略一堆逻辑
。。。。
return new ParameterHandler.Tag<>(tagType);
}
return null; // Not a Retrofit annotation.
}
所有的根据注解生成具体的ParameterHandler都是继承自ParameterHandler,在生成真正的okhttp3.Request请求的时候是会调用复写ParameterHandler的apply(RequestBuilder builder, @Nullable T value)方法,以实现生成符合http规范的请求头,请求参数,请求体。后文会继续分析apply调用的时机。
static HttpServiceMethod parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();
Type adapterType;
if (isKotlinSuspendFunction) {//是否是Kotlin的suspend方法,因为我们定义在API接口GitHub里面的方法不是suspend,此处为false
Type[] parameterTypes = method.getGenericParameterTypes();
Type responseType = Utils.getParameterLowerBound(0,
(ParameterizedType) parameterTypes[parameterTypes.length - 1]);
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
// Unwrap the actual body type from Response.
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
// TODO figure out if type is nullable or not
// Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
// Find the entry for method
// Determine if return type is nullable or not
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();//方法的返回类型
}
//重点1,找到对应的callAdapter
CallAdapter callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
if (responseType == okhttp3.Response.class) {
throw methodError(method, "'"
+ getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
if (responseType == Response.class) {
throw methodError(method, "Response must include generic type (e.g., Response)");
}
// TODO support Unit for Kotlin?
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
//重点2,找到对应的Converter
Converter responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
//重点3,我们用到是CallAdapted
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//针对kotlin的非suspend方法
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod) new SuspendForResponse<>(requestFactory,
callFactory, responseConverter, (CallAdapter>) callAdapter);
} else {//针对kotlin的suspend方法
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod) new SuspendForBody<>(requestFactory,
callFactory, responseConverter, (CallAdapter>) callAdapter,
continuationBodyNullable);
}
}
}
进入createCallAdapter方法看看逻辑
private static CallAdapter createCallAdapter(
Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
try {
//noinspection unchecked
return (CallAdapter) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create call adapter for %s", returnType);
}
}
是调用的Retrofit的callAdapter方法,进去看一下,分析逻辑见注释。
public CallAdapter nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
//callAdapter传入的skipPast为null,因此callAdapterFactories.indexOf(skipPast)的值为-1,因此start为0
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
//返回的是callAdapterFactories里面符合要要求的CallAdapter,前面的Retrofit的Builder在builder函数中
//默认添加了[CompletableFutureCallAdapterFactory,DefaultCallAdapterFactory]或者[DefaultCallAdapterFactory]
//如果用户不添加其他的CallAdapterFactory的话,我们在Github的API中返回值的类型是Call> ,returnType是Call.class类型的,
//DefaultCallAdapterFactory恰好是针对Call.class,CompletableFutureCallAdapterFactory是针对CompletableFuture.class,
//因此拿到的是DefaultCallAdapterFactory,返回的是DefaultCallAdapterFactory,生成的
CallAdapter adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
.append(returnType)
.append(".\n");
if (skipPast != null) {
builder.append(" Skipped:");
for (int i = 0; i < start; i++) {
builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());
}
builder.append('\n');
}
builder.append(" Tried:");
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());
}
throw new IllegalArgumentException(builder.toString());
}
通过上面分析可以知道,得到的是DefaultCallAdapterFactory通过get( Type returnType, Annotation[] annotations, Retrofit retrofit)方法拿到的CallAdapter,我们进入看一下
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
private final @Nullable Executor callbackExecutor;
DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override public @Nullable CallAdapter get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
if (!(returnType instanceof ParameterizedType)) {
throw new IllegalArgumentException(
"Call return type must be parameterized as Call or Call");
}
//返回形如Call或者 Call中Foo的类型
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
//此处创建了一个CallAdapter
return new CallAdapter
// Create a call instance for looking up Retrofit contributors.
Call> call = github.contributors("square", "retrofit");
// Fetch and print a list of the contributors to the library.
List contributors = call.execute().body();
此时的call实际上是OkHttpCall,我们进入OkHttpCall的excute方法
final class OkHttpCall implements Call {
@GuardedBy("this")
private @Nullable okhttp3.Call rawCall;
@GuardedBy("this") // Either a RuntimeException, non-fatal Error, or IOException.
private @Nullable Throwable creationFailure;
@GuardedBy("this")
private boolean executed;
@Override public Response 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 if (creationFailure instanceof RuntimeException) {
throw (RuntimeException) creationFailure;
} else {
throw (Error) creationFailure;
}
}
call = rawCall;
//一开始rawCall为null,必然会调用createRawCall()
if (call == null) {
try {
call = rawCall = createRawCall();
} catch (IOException | RuntimeException | Error e) {
throwIfFatal(e); // Do not assign a fatal error to creationFailure.
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
//执行的是createRawCall生成的call的execute()方法
return parseResponse(call.execute());
}
private okhttp3.Call createRawCall() throws IOException {
//callFactory为OkHttpClient
//requestFactory为调用ServiceMethod.parseAnnotations(Retrofit retrofit, Method method)方法体里面
//RequestFactory.parseAnnotations(retrofit, method);返回的值
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
}
okhttp3.Request create(Object[] args) throws IOException {
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler[] handlers = (ParameterHandler[]) parameterHandlers;
int argumentCount = args.length;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
//Retrofit初始化的时候传入的baseUrl,方法解析的时候获取到的请求类型,
//相对路径,请求头,请求内容的类型,是否带有方法体是否编码等
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
headers, contentType, hasBody, isFormEncoded, isMultipart);
//针对kotlin的suspend方法处理
if (isKotlinSuspendFunction) {
// The Continuation is the last parameter and the handlers array contains null at that index.
argumentCount--;
}
List argumentList = new ArrayList<>(argumentCount);
for (int p = 0; p < argumentCount; p++) {
argumentList.add(args[p]);
//重点,前面在解析方法参数注解的时候生成了很多ParameterHandler,通过ParameterHandler的apply
//方法将这些注解关联的内容配置到RequestBuilder里面
//例如是@Head则调用RequestBuilder.addHeader(String name, String value)
//是@Path则调用RequestBuilder.addPathParam(String name, String value, boolean encoded)
handlers[p].apply(requestBuilder, args[p]);
}
//RequestBuilder.get()方法返回的的是Request.Builder 类型,跟RequestBuilder不是一个类型
//可以理解为RequestBuilder的get()方法相当于一个build()方法,只不过生成不是Request类型
//而是Request.Builder类型,而Request.Builder的build()方法返回的才是Request
return requestBuilder.get()
.tag(Invocation.class, new Invocation(method, argumentList))
.build();
}
Task not serializable是Spark开发过程最令人头疼的问题之一,这里记录下出现这个问题的两个实例,一个是自己遇到的,另一个是stackoverflow上看到。等有时间了再仔细探究出现Task not serialiazable的各种原因以及出现问题后如何快速定位问题的所在,至少目前阶段碰到此类问题,没有什么章法
1.
package spark.exampl
mysql 查看当前正在执行的操作,即正在执行的sql语句的方法为:
show processlist 命令
mysql> show global status;可以列出MySQL服务器运行各种状态值,我个人较喜欢的用法是show status like '查询值%';一、慢查询mysql> show variab
1. 只有Map任务的Map Reduce Job
File System Counters
FILE: Number of bytes read=3629530
FILE: Number of bytes written=98312
FILE: Number of read operations=0
FILE: Number of lar
import java.util.LinkedList;
import java.util.List;
import ljn.help.*;
public class BTreeLowestParentOfTwoNodes {
public static void main(String[] args) {
/*
* node data is stored in
本文介绍Java API 中 Date, Calendar, TimeZone和DateFormat的使用,以及不同时区时间相互转化的方法和原理。
问题描述:
向处于不同时区的服务器发请求时需要考虑时区转换的问题。譬如,服务器位于东八区(北京时间,GMT+8:00),而身处东四区的用户想要查询当天的销售记录。则需把东四区的“今天”这个时间范围转换为服务器所在时区的时间范围。
入口脚本
入口脚本是应用启动流程中的第一环,一个应用(不管是网页应用还是控制台应用)只有一个入口脚本。终端用户的请求通过入口脚本实例化应用并将将请求转发到应用。
Web 应用的入口脚本必须放在终端用户能够访问的目录下,通常命名为 index.php,也可以使用 Web 服务器能定位到的其他名称。
控制台应用的入口脚本一般在应用根目录下命名为 yii(后缀为.php),该文