整体Retrofit内容如下:
1、Retrofit解析1之前哨站——理解RESTful
2、Retrofit解析2之使用简介
3、Retrofit解析3之反射
4、Retrofit解析4之注解
5、Retrofit解析5之代理设计模式
6、Retrofit解析6之面向接口编程
7、Retrofit解析7之相关类解析
8、Retrofit解析8之核心解析——ServiceMethod及注解1
9、Retrofit解析8之核心解析——ServiceMethod及注解2
10、Retrofit解析9之流程解析
11、Retrofit解析10之感谢
从本文开始,开始正式解析Retrofit源码,本文的结构如下:
1、解析思路 2、Call接口 3、CallAdapter接口 4、Callback接口 5、Converter接口 6、ExecutorCallAdapterFactory类 7、Platform类 8、HttpException类 9、面向接口编程
一、解析思路:
(一)、假设
在讲解,解析思路之前,我们先想一下,那么想什么那?如果让你"设计"一个类似Retrofit的库,你要怎么"设计"那? 注意是重点是 "设计" ,不是 "写" 。 那怎么 "设计" 那?那我先说我的思路,如果是我,我先想摸清需求 需求如下:
1、首先要解耦,请求和构建请求分离,所以必须在这里"库"里面组建一个Call来和okHttp里面的Call对应
2、有返回值的时候给外部调用的回调。
3、如果需要把响应内部的响应体
4、支持响应体自动反序列化。
所以如果我让我设计这么一个库,必须先写三个接口,每个接口对应上面的一个问题。这里我们又想到一个Call和转换,是两个需求,根据单一原则,应该是四个接口 分别是:
1、一个接口表征一个HTTP请求
2、一个类型转化接口,负责本地库的HTTP请求与其他类型的转化,比如转化为RxJava,既然请求可以转化,那么响应的返回值转化也应该在这里做。
3、序列化与反序列化操作
4、响应回调的处理
所以我在设计的时候,肯定要设计这四个接口,然后在围绕这四个接口进行操作,这是我的设计思想,那你们的那?
下面看下他的类目录结构
如上图所示,有4个接口
Call接口
CallAdapter接口
Callback接口
Converter接口 这四个接口是不是刚好对上我的那个四个接口。如果大家对面向接口编程不是很熟悉,没关系,在本篇文章的最后一部分,我单独给大家讲解下,我所理解的相面接口编程。那么我们先来看下这几个接口。
二、Call接口
(一)、思考
两个问题:
1、在看这个这接口的时候,大家想下,Retrofit为什么要创建这个接口,并且命名为Call,先思考5分钟。再看下面的内容。
2、如果让你"设计"这个Call接口你要怎么设计
————————分割线,思考上面的问题——————————
不知道你们的想法,不过我先说下我的想法
第一个问题 我是这么想的
这个Call 肯定模拟了一个客户端发起请求到服务器,然后服务器响应数据到客户端的整个流程。通过这个Call我们可以获取相应的请求和相应的信息。
第二个问题 我是这样想的
既然是模拟了整个请求和响应逻辑,所以肯定要设计一个发起请求的方法,来模拟发请求;既然是请求,所以必然包含一个同步请求的方法,表征同步请求,设计一个异步请求的方法,表征一个异步请求;还要设计一个取消请求的的方法,表征一个取消请求的方法。我能想到就是这么多了,你们的那?
OK,那我们来看下这个接口的源码看下Retrofit是怎么设计的。
(二)、来看下接口的源码
/**
* An invocation of a Retrofit method that sends a request to a webserver and returns a response.
* Each call yields its own HTTP request and response pair. Use {@link #clone} to make multiple
* calls with the same parameters to the same webserver; this may be used to implement polling or
* to retry a failed call.
*
*
Calls may be executed synchronously with {@link #execute}, or asynchronously with {@link
* #enqueue}. In either case the call can be canceled at any time with {@link #cancel}. A call that
* is busy writing its request or reading its response may receive a {@link IOException}; this is
* working as designed.
*
* @param Successful response body type.
*/
public interface Call extends Cloneable {
/**
* Synchronously send the request and return its response.
*
* @throws IOException if a problem occurred talking to the server.
* @throws RuntimeException (and subclasses) if an unexpected error occurs creating the request
* or decoding the response.
*/
Response execute() throws IOException;
/**
* Asynchronously send the request and notify {@code callback} of its response or if an error
* occurred talking to the server, creating the request, or processing the response.
*/
void enqueue(Callback callback);
/**
* Returns true if this call has been either {@linkplain #execute() executed} or {@linkplain
* #enqueue(Callback) enqueued}. It is an error to execute or enqueue a call more than once.
*/
boolean isExecuted();
/**
* Cancel this call. An attempt will be made to cancel in-flight calls, and if the call has not
* yet been executed it never will be.
*/
void cancel();
/** True if {@link #cancel()} was called. */
boolean isCanceled();
/**
* Create a new, identical call to this one which can be enqueued or executed even if this call
* has already been.
*/
Call clone();
/** The original HTTP request. */
Request request();
老规矩先看下类的注释 我简单的翻译一下: 通过调用Retrofit的方法向web服务器发送请求并返回响应。每一次调用都产生自己的HTTP请求和对应的响应 对儿。如果出现了在避免轮询或者失败重试的情况,可以 调用clone()方法 复制 可以对具有相同的web服务器进行 具有相同参数的 请求。 同步调用 采用execute方法,异步采用enqueue方法,在任何情况下, 一个请求Call 都有可以通过cancel取消,一个Call在写入请求或读取响应的时候是可能产生IOExcetption的,这是再正常不过的了。 参数 是成功的响应体类型
看下他的方法
和大家设计的一样吗?我是少了三个方法,分别是
boolean isExecuted(); 判断是否正在运行中
sCanceled(); 判断是否已经取消了
Call clone(); 复制一个连接,为了轮训和请求失败的时候用
这里温馨提示下:
Request request();
里面的返回值是okhttp3.Request。这里返回是okHttp的request。大家怎么看这个情况,我的理解是在接口层面指定了okHttp的request,则指明了底层的请求只能使用okHttp了
PS:大家注意一下这个接口和okhttp3.Call的接口基本上一致,只不过多了一个clone()方法。
这个接口,目前就研究结束了,不知道大家怎么看待这个接口,希望大家看完这个接口的介绍,心里对Call这个接口有一个比较深刻的认识
三、CallAdapter接口
(一)、思考
同样两个问题?
1、retrofit为什么要设计这个类?
2、如果让我们设计,我们怎么设计这个接口
————————分割线,思考上面的问题——————————
不知道你们的想法,不过我先说下我的想法 第一个问题 我是这么想的
我们知道retrofit是支持RxJava的,那么如果一个RxJava是需要转化成一个Retrofit中的Call,那肯定需要一个适配器,把一个RxJava的Observable适配成一个Retrofit的Call,所以设计这个类的主要目的就是适配让Retrofit的Call对业务层的请求适配,这样整个结构更清晰。
第二个问题 我是这样想的
首先上面说了,既然是适配,肯定要有一个方法要去做适配把Retrofit的Call适配成业务方自定义的"Call"。其次,大家知道Retrofit的Call的泛型T是response的Body,这个类型是泛型,所以最后反序列化的时候需要反序列化成一个对象,这个需要指定这个对象的类型,所以还应该获取这个类的具体"类型"。
这是我之前的想法,大家的想法如何?那我们来仔细看一下他的源代码
(二)、读源码
/**
* Adapts a {@link Call} with response type {@code R} into the type of {@code T}. Instances are
* created by {@linkplain Factory a factory} which is
* {@linkplain Retrofit.Builder#addCallAdapterFactory(Factory) installed} into the {@link Retrofit}
* instance.
*/
public interface CallAdapter {
/**
* Returns the value type that this adapter uses when converting the HTTP response body to a Java
* object. For example, the response type for {@code Call} is {@code Repo}. This type
* is used to prepare the {@code call} passed to {@code #adapt}.
*
* Note: This is typically not the same type as the {@code returnType} provided to this call
* adapter's factory.
*/
Type responseType();
/**
* Returns an instance of {@code T} which delegates to {@code call}.
*
* For example, given an instance for a hypothetical utility, {@code Async}, this instance would
* return a new {@code Async} which invoked {@code call} when run.
*
* @Override
* public Async adapt(final Call call) {
* return Async.create(new Callable>() {
* @Override
* public Response call() throws Exception {
* return call.execute();
* }
* });
* }
*
*/
T adapt(Call call);
/**
* Creates {@link CallAdapter} instances based on the return type of {@linkplain
* Retrofit#create(Class) the service interface} methods.
*/
abstract class Factory {
/**
* Returns a call adapter for interface methods that return {@code returnType}, or null if it
* cannot be handled by this factory.
*/
public abstract CallAdapter get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
/**
* Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
* example, index 1 of {@code Map} returns {@code Runnable}.
*/
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
/**
* Extract the raw class type from {@code type}. For example, the type representing
* {@code List} returns {@code List.class}.
*/
protected static Class getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
1、老规矩先来看下 类 的注释:
将一个Call和他的响应类型R适配成T类型。实例由对应的Factory来创建,这个对应的Factory是通过Retrofit.Builder的addCallAdapterFactory(Factory)方法添加到Retrofit对象中的,在上述的过程中实现的初始化。
再来看下他两个方法的注释
2、看下他的Type responseType()方法的注释
返回此适配器将HTTP响应body转换为Java对象时使用的类型。 例如,"Call "的响应类型是"Repo"。 此类型用于准备传递给"adapt"的"call"。 注意:这通常与提供给此呼叫适配器工厂的"returnType"不同。
3、看下他的 T adapt(Call call)方法的注释
T 就是代表Retrofit里面Call的一个实例。后面的我实在是翻译不好,对不起大家了,其实说白了就是讲一个Retrofit的Call 是适配成另外一个"Call"
4、看下他的子类 abstract class Factory
看上面的源码大家知道Factory是个子类,一般用Factory都是工厂模式。 老规矩看下他的 ***类**** 的注释,翻译一下就是
基于Retrofit的create方法的返回值创建CallAdapter实例。
看完上面的注释,大家应该发现了Retrofit的一个规律就是:retrofit定义了CallAdapter接口,内部有定义了一个Factory,工厂方法定义了如何生成CallAdapter,而CallAdapter又定义了如何拿到业务层定义的"Call"。所以他们的顺序如下:CallAdapter.Factory——>CallAdapter——>自定义的"Call"。
再来看下他的几个方法
public abstract CallAdapter get(Type returnType, Annotation[] annotations, Retrofit retrofit) 的注释:返回一个CallAdapter的实例,如果工厂无法处理则返回null。(注意:抽象的方法,需要子类去实现的)
Type getParameterUpperBound(int index, ParameterizedType type) 注释: 已知指定位置(index) 对应的类型(type) 来获取泛型中的通配符的参数的上线,例如:Map ,则返回Runnable。(静态方法,有具体的实现)
static Class getRawType(Type type) 注释:提取type对应的原始类型。例如:List 则返回List.class
四、Callback接口
这个接口就比较简单了,就不用大家思考了,Callback看字面意思就是回调,里面肯定一个是成功的回调,一个是错误的回调。直接读下源码
/**
* Communicates responses from a server or offline requests. One and only one method will be
* invoked in response to a given request.
*
* Callback methods are executed using the {@link Retrofit} callback executor. When none is
* specified, the following defaults are used:
*
* Android: Callbacks are executed on the application's main (UI) thread.
* JVM: Callbacks are executed on the background thread which performed the request.
*
*
* @param Successful response body type.
*/
public interface Callback {
/**
* Invoked for a received HTTP response.
*
* Note: An HTTP response may still indicate an application-level failure such as a 404 or 500.
* Call {@link Response#isSuccessful()} to determine if the response indicates success.
*/
void onResponse(Call call, Response response);
/**
* Invoked when a network exception occurred talking to the server or when an unexpected
* exception occurred creating the request or processing the response.
*/
void onFailure(Call call, Throwable t);
1、先看下 类 的注释
从服务器或离线请求的对应的响应(response)。 对应指定请求的,有且仅有一个方法与其对应。 由Retrofit的callback executor执行回调方法。当没有指定时,使用下面的默认值: 如果是 Android:回调在应用程序的主(UI)线程上执行,如果是JVM,则在执行请求的后台线程上执行回调。 泛型参数 代表成功的响应类的类型
这个接口就两个方法,一个对应成功的回调,一个对应失败的回调
1、void onResponse(Call call, Response response) 注释:调用接收的HTTP响应。注意:HTTP响应可能是指示应用程序级别的故障,例如404或500。调用 Response的isSuccessful()方法来判断响应是否成功。
2、void onFailure(Call call, Throwable t) :注释:当与服务器交互时、当创建请求、当处理响应时产生Exception 均调动该方法。
五、Converter接口
Converter我认为挺简单的,就是负责类型转换
(一)、思考
一个问题:
1、如果让你"设计"这个Converter接口你要怎么设计 ————————分割线,思考上面的问题—————————— 这个问题 我是这么想的
因为是给网络场景下的使用的,我的第一反应是写两个方法,一个方法是在请求的时候,写数据进行序列化的时候;还有一个就是在响应的时候, 读取数据进行反序列化的时候。
(二)、源码
/**
* Convert objects to and from their representation in HTTP. Instances are created by {@linkplain
* Factory a factory} which is {@linkplain Retrofit.Builder#addConverterFactory(Factory) installed}
* into the {@link Retrofit} instance.
*/
public interface Converter {
T convert(F value) throws IOException;
/** Creates {@link Converter} instances based on a type and target usage. */
abstract class Factory {
/**
* Returns a {@link Converter} for converting an HTTP response body to {@code type}, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for
* response types such as {@code SimpleResponse} from a {@code Call}
* declaration.
*/
public Converter responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
/**
* Returns a {@link Converter} for converting {@code type} to an HTTP request body, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for types
* specified by {@link Body @Body}, {@link Part @Part}, and {@link PartMap @PartMap}
* values.
*/
public Converter requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
/**
* Returns a {@link Converter} for converting {@code type} to a {@link String}, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for types
* specified by {@link Field @Field}, {@link FieldMap @FieldMap} values,
* {@link Header @Header}, {@link HeaderMap @HeaderMap}, {@link Path @Path},
* {@link Query @Query}, and {@link QueryMap @QueryMap} values.
*/
public Converter stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
}
}
1、看下类的注释
在HTTP请求中实现对象的转化。Converter这个类的实例由Factory创建。而这个Factory则由Retrofit.Builder的addConverterFactory()方法来进行初始化的
这个接口的抽象方法比较少,就一个
T convert(F value) throws IOException
不用注释,大家也知道把F 转化为T,这个接口是有两个参数的,我把F称为转入类型,T为转出类型,因为要把F转化为T。
哎 好像和我想象的不一样哎,那我们继续看下他的抽象类Factory
2、抽象类Factory
看名字就知道是个工厂类,肯定是通过这个工厂来产生Converter对象。
(1)、看下类的注释
基于类型和目标来创建一个Converter的实例
(2)、看下对应的三个方法的注释
1、public Converter responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) 注释 :返回一个处理HTTP 响应的的body的Converter(转换器),转入类型ResponseBody,如果因为type(类型)无法处理,工厂无法处理,则返回null。例如:一个Retrofit的Call是Call,则对应的响应body的类型应该是 SimpleResponse。
2、Converter requestBodyConverter(Type type,Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) 注释 :返回一个可以处理将HTTP的请求(resquest)中的body的Converter对象,转出类型是RequestBody。如果因为type(类型)无法处理,则返回null。这个Converter主要是为了处理@Body 注解,@Part 注解,@PartMap的类型转换。
3、Converter stringConverter(Type type, Annotation[] annotations,Retrofit retrofit) 注释 :支持返回一个转出类型为String的Converter实例。如果类型不能处理,则返回null。这个主要是为了 @Field,FieldMap,@FieldMap , @Header, @HeaderMap, @Path, @Query, @QueryMap 这些注解创建的 @Converter转换器
(3)、总结
Retrofit 明显想的比我多,设计比我优雅,那我们来总结下这个接口
1、Converter 这个类的职责主要是做** 类型转化 **,Retrofit定义了Converter,但是接口内部有个内部类负责创建Converter。
2、大家注意到没Factory虽然是个抽象类,但是他的三个方法都不是抽象方法。
3、Factory的三个方法目的不一样,都的是真针对请求体,有的针对响应体。
六、ExecutorCallAdapterFactory
上文讲解Platform中的静态内部类Android的defaultCallAdapterFactory方法里面返回的是一个ExecutorCallAdapterFactory的对象。那我们就在讲解下ExecutorCallAdapterFactory类
(一)、上源码
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
// get方法,创建并返回Android平台默认CallAdapter
@Override
public CallAdapter get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
//先判断原始类型是不是Call,这个Call是retrofit包下的Call
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call adapt(Call call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
static final class ExecutorCallbackCall implements Call {
final Executor callbackExecutor;
final Call delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback callback) {
if (callback == null) throw new NullPointerException("callback == null");
delegate.enqueue(new Callback() {
@Override public void onResponse(Call call, final Response response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
@Override public boolean isExecuted() {
return delegate.isExecuted();
}
@Override public Response execute() throws IOException {
return delegate.execute();
}
@Override public void cancel() {
delegate.cancel();
}
@Override public boolean isCanceled() {
return delegate.isCanceled();
}
@SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
@Override public Call clone() {
return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
}
@Override public Request request() {
return delegate.request();
}
}
}
麻蛋,又是一个没有注释的类,不过通过源码我们知道这是一个final类,不能被继承。
首先这个ExecutorCallAdapterFactory类实现了CallAdapter.Factory,所以必然实现了CallAdapter.Factory接口的方法,我们来看下这个get方法内部的实现流程
1、首先判断原始类型
2、通过调用Utils.getCallResponseType()获取** "响应" **(不是"相应")的类型。
3、new了一个CallAdapter的匿名内部类,注意这个CallAdapter的两个泛型分别是Object和Call,这个CallAdapter的两个抽象方法的实现:(1)、Type responseType返回的是第2步产生的"响应"类型;(2)、Call adapt(Call call) 方法返回的是 new的一个ExecutorCallbackCall对象。
ExecutorCallbackCall是个神马东西,原来ExecutorCallbackCall是ExecutorCallAdapterFactory的静态内部类,那么我们来分析一下ExecutorCallAdapterFactory类。
(二)、ExecutorCallbackCall类分析
1、上源码
static final class ExecutorCallbackCall implements Call {
final Executor callbackExecutor;
final Call delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback callback) {
if (callback == null) throw new NullPointerException("callback == null");
delegate.enqueue(new Callback() {
@Override public void onResponse(Call call, final Response response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
@Override public boolean isExecuted() {
return delegate.isExecuted();
}
@Override public Response execute() throws IOException {
return delegate.execute();
}
@Override public void cancel() {
delegate.cancel();
}
@Override public boolean isCanceled() {
return delegate.isCanceled();
}
@SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
@Override public Call clone() {
return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
}
@Override public Request request() {
return delegate.request();
}
}
2、看上面源码我们能得知如下内容:
1、ExecutorCallbackCall实现了Retrofit里面的Call接口,所以ExecutorCallbackCall是Retrofit里面的Call的实现类,所以必然实现了对应Call的抽象类。
2、如果想要构造一个ExecutorCallbackCall对象,必须传入一个Executor和Call两个对象才行。
3、无论是发起同步请求还是异步请求,或者取消请求,其实真正的操作对象是,构造时传入的delegate。
4、无论同步,还是异步,调用的线程池都是 ,构造时传入的callbackExecutor,而在Android那部分我们知道callbackExecutor其实就是MainThreadExecutor,所以最后无论同步还是异步,最后都会切换到UI主线程中去
3、所以总结一下ExecutorCallbackCall类
它实现了Call这个接口,Call我们前面说了,就是一个网络请求,然而我们这里看到这里并没有做实际请求,而是用了一个静态代理,通过这个delegate代理来实现call的请求,而在这里面做了一些其他的逻辑比如cancel逻辑,而实际上做这个请求还是交给了delegate。(其实OkHttpCall)
(三) ExecutorCallAdapterFactory 类总结
ExecutorCallAdapterFactory是CallAdapter.Factory的实现类,ExecutorCallAdapterFactory是将Call 适配成Call接口。但适配前和适配后的Call 还是不一样的,从enqueue方法中可以看到在callbackExecutor执行了回调,callbackExecutor上文已经介绍了,在Android平台就是UI主线程。
七、Platform类
为了方便大家后期更好的理解源码,我先给大家介绍一下Platform。这个Platform是个神马东东,字面理解是"平台",有啥神功疗效? 工欲善其事必先利其器,我们先来看下源码
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
Executor defaultCallbackExecutor() {
return null;
}
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
if (callbackExecutor != null) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapterFactory.INSTANCE;
}
boolean isDefaultMethod(Method method) {
return false;
}
Object invokeDefaultMethod(Method method, Class declaringClass, Object object, Object... args)
throws Throwable {
throw new UnsupportedOperationException();
}
@IgnoreJRERequirement // Only classloaded and used on Java 8.
static class Java8 extends Platform {
@Override boolean isDefaultMethod(Method method) {
return method.isDefault();
}
@Override Object invokeDefaultMethod(Method method, Class declaringClass, Object object,
Object... args) throws Throwable {
// Because the service interface might not be public, we need to use a MethodHandle lookup
// that ignores the visibility of the declaringClass.
Constructor constructor = Lookup.class.getDeclaredConstructor(Class.class, int.class);
constructor.setAccessible(true);
return constructor.newInstance(declaringClass, -1 /* trusted */)
.unreflectSpecial(method, declaringClass)
.bindTo(object)
.invokeWithArguments(args);
}
}
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);
}
}
}
}
这个类好坑啊,居然没有注释,不过通知字面的意思,我们
(一)、初始化
Platform 的初始化
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
Platform字面的意思就是平台。所以Platform其实就是一个父类,不同平台对应不同的实现子类。Android、Java 8 对应的是各种具体平台。可以看到,调用findPlatform()方法之后就回去判断对应的平台,具体实现的子类就是Android 和Java。
这里提一下我的小插曲,按照我之前分析okHttp的思路,okHttp里面也有Platform。所以我直接在Retrofit的包下找AndroidPlatform,结果发现没有,我就蒙圈了,后来才发现在Platform的内部类里面,汗.....
由于我们针对Android平台关于Java的具体设置,我就不讲解了,这里看下对应的Platform的内部类Anroid
(二)、Android
Android是Platform的静态内部类 代码很简介,如下:
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
}
而Android类就两个方法,一个是defaultCallbackExecutor,另外一个是defaultCallAdapterFactory,从字面的意思我们可以知道,defaultCallbackExecutor()这个方法应该是返回的是默认的回调的线程池容器,defaultCallAdapterFactory()方法返回的是默认的请求适配工厂(CallAdapterFactory)。
那MainThreadExecutor是什么东西?原来MainThreadExecutor是Android的静态内部类。那我们来看下MainThreadExecutor这个类
(三)、MainThreadExecutor
看字面意思,我的理解是主线程的线程池。 来看下源码:
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
代码很简单,通过new Handler(Looper.getMainLooper())来获取一个主线程的Handler。然后在执行主线程的时候,调用的是主线程的handler的post方法。
ExecutorCallAdapterFactory 这个类 我们在下面讲解。
(四)、总结
Platform 其实就是一个"平台",定义了一些平台共有的方法,然后也针对不同的平台定义了一些不同的具体实现子类,比如各个不同平台根据不同环境来初始化不同的MainThreadExecutor。这里也可以看到,在初始化Platform之后,通过Platform得到的ExecutorCallAdapterFactory的工厂的Excecutor其实就是运行在主线程的Executor。
八 HttpException类
这个类比较简单,就不用想了,肯定肯定是Retrofit处理异常的的异常包装类,代码不多,直接上源码:
/** Exception for an unexpected, non-2xx HTTP response. */
public class HttpException extends Exception {
private static String getMessage(Response response) {
if (response == null) throw new NullPointerException("response == null");
return "HTTP " + response.code() + " " + response.message();
}
private final int code;
private final String message;
private final transient Response response;
public HttpException(Response response) {
super(getMessage(response));
this.code = response.code();
this.message = response.message();
this.response = response;
}
/** HTTP status code. */
public int code() {
return code;
}
/** HTTP status message. */
public String message() {
return message;
}
/**
* The full HTTP response. This may be null if the exception was serialized.
*/
public Response response() {
return response;
}
}
通过注释我们知道,这个HttpException主要是用来处理意外的、非2xx的响应异常 这个类就三个变量
int code :http的状态code,比如:405、501等
String message : http状态的信息
Response response : 服务器的响应 这个三个参数在构造函数里面进行初始化的,由于这三个变量分别是private ,所以必然有一个对应的get方法。不过这里的方法并没有以"get"开头。
最后他又定义了 静态方法getMessage(Response),传入一个Response,返回一个拼接的String。
PS:
HttpException 里面的Response是Retrofit里面的Response,OkHttp里面也有一个Response。大家不要混淆了!
这个类比较简单,只能讲这么多了
九、面向接口编程
面向接口编程
Interface-based programming, also known as interface-based architecture, is an architectural pattern for implementing modular programming at the component level in an object-oriented programming language which does not have a module system.
翻译一下:
面向接口编程,也被熟知为基于接口的设计,是一种基于组件级别的,面向对象语言的模块化编程设计实现。
说道面向接口不得不说面向对象,不过面向接口编程和面向对象编程实际上两个不同层级的概念。理论上说具有对象概念的程序设计都可以称之为面向对象编程,而面向接口编程则是从组件的级别来设计代码,认为地将抽象与实现分离。面向接口编程仅仅是面向对象编程的一种模块化实现形式而已。
(一)所谓的“接口”
面向接口编程中的"接口" 二字具体到Java语言中不仅仅是"interface"关键字这么简单。可以理解为接口是对具体实现的抽象。试想一下,团队协同以及代码健壮可维护性的需求日益增强的趋势下,通过暴露接口来提供服务本身是一件非常愉悦的事情。A需要调用B的服务,A却不需要去仔细阅读B写的代码,通过接口文档就可以看出对应业务的方法和参数类型,进而使用RMI或者RPC等相关技术实现模块化的调用。而这一切本身就是相面接口编程。
换一种角度,我们怎么定义接口:“接口泛指实体把自己提供给外界的一种抽象化物,用以由内部操作分离出外部沟通方法,使其能被修改内部而不影响外界其他实体与其交互的方式”,话句话说,在我们程序的世界里,接口的作用就是用于定义一个或一组规则,实现对应接口的实体需要遵循对应的这些规则。也可以说是对“同类事物”的抽象表示,而“同类事物”的界定就看是否实现了同一个接口,譬如一个Animal接口和NightWorking接口,公鸡实现了Animal接口,猫头鹰实现了Animal接口和NightWorking接口,还有一个实现了NightWorking的接口的酒吧,在Animal的范畴下,我们可以称公鸡和猫头鹰是同类事物,但是在NightWorking的范畴下,我们可以把我们可以称猫头鹰和酒吧是同类事物。有点恐怖吧
很多刚刚接触面向接口编程的Java开发者会认为,既然面向接口编程,那么就把实现抽象为接口就是优良的设计。但实际上他们混淆了Java中的interface和面向接口编程的"接口的"概念。实际上,interface、abstract class以及普通的class 都能成为所谓的接口,甚至 abstract class的功能可以更加强大。那么interface和abstract class 区别是什么?
(二)、abstract class和interface的区别:
abstract class和interface的区别在于,interface约定的是务必实现的方法,强调的是规则的制定。abstract class则是在抽象的同时允许提供一些默认的行为,以达到代码复用的效果。例如一定一些基础、初始化以及类回收方法等。另外,还有一个常识性的区别,一个实现类(相对于抽象而言)可以实现多个interface,而只能继承一个abstract class,在代码设计的过程中务必注意。
(三)、面向接口的优势:
1、方便程序使用多态 例如有方法需要一个集合类型的参数,将参数设置为List类型和设置成ArrayList相比,入惨不仅可以传入ArrayList类型还可以是LinkedList类型,因此代码使用范围更广。
2、代码扩展性更强 如果要扩展一个类的方法,我们一般可以选择动态代理方式来对某些方法进行增强,但是动态代理的类需要实现接口,这也是面试接口编程的一大优势。
3、降低了代码间的耦合 例如:计算机Computer类有一个IStrorage接口类型和成员变量,接口定义了write和read方法,移动设备类FlashDisk,MP3类实现了IStrorage接口,那么计算Computer类和FlashDisk、MP3就能关联成功,但是Computer并不知道自己的成员变量是什么具体类型,这就是所有的"依赖几口,而不依赖具体类"。Java中两个层面之间通过接口产生联系,此时接口相当于一个缓冲区,当业务发生改变,只改变实现类的代码即可,必须要改写后续代码,减少对整个系统的影响。
(四)、 面向接口的编程方式
"定义接口"——"定义类": 先定义接口,再实现类
任何需要在函数间传入传出的一定是接口而不是具体的类,面向接口的编程方式是Java成功关键之一,因为适合多人同时开发。
一方只认识接口,想进入另一方,就披上那个接口外套吧。
你可能感兴趣的:(Retrofit解析6之面向接口编程)
dp 1.4协议_DP接口与HDMI接口各有什么优势?哪个更好?
喵星人向前冲
dp 1.4协议
一、DP接口DisplayPort缩写DP,与目前主流的HDMI接口均属于数字高清接口,都支持一根信号线同时传输视频和音频信号,DP接口从第一代就达到了10.8Gbps带宽,支持2560x160012bit输出。目前市面最多的DP1.2已经高达21.6Gbit/s超越了HDMI2.0,支持1080P240、2K165、4K75、5K30。DP1.3支持2K240、4K120、8K30。最新的DP1
dp 1.4协议_DP接口与HDMI接口的区别?
刘震撼
dp 1.4协议
有朋友问到关于DP和HDMI哪个更好?这个在我们实际项目中也经常会遇到,之前我们也曾提到过,本期我们再来详细总结下。一、dp接口DisplayPort缩写DP,与目前主流的HDMI接口均属于数字高清接口,都支持一根信号线同时传输视频和音频信号,DP接口从第一代就达到了10.8Gbps带宽,支持2560x160012bit输出。目前市面最多的DP1.2已经高达21.6Gbit/s超越了HDMI2.0
20250304在飞凌OK3588-C的linux R4下提高温度控制阈值为95度
南棱笑笑生
杂质 java 算法 linux
20250304在飞凌OK3588-C的linuxR4下提高温度控制阈值为95度2025/3/415:56缘起:我司应用工程师需要调用NPU来进行AI识别/检测,CPU/核心板在有塑胶外壳的情况下满负荷工作,风扇也压不住^_权衡之后还是提高温度阈值到95度了。@程帅?程工,请问rk3588的温度控制降频怎么关闭,我设置了温控策略为user_space,但是测试cpu核心温度到了85度还是会出现降频
2020年“磐云杯”网络空间安全技能竞赛全国拉赛
Beluga
中职网络空间安全赛题 安全 linux 网络 网络空间安全 中科磐云
2020年“磐云杯”网络空间安全技能竞赛全国拉赛一、竞赛阶段竞赛阶段任务阶段竞赛任务竞赛时间分值第一阶段单兵模式系统渗透测试任务1Wireshark数据包分析100分钟100任务2系统漏洞扫描与利用100任务3服务漏洞扫描于测试100任务4Web渗透测试100任务5Windows操作系统渗透测试100任务6Linux操作系统渗透测试100任务7主机存活扫描渗透测试100备战阶段攻防对抗准备工作20
如何使用BeautifulSoup轻松解析网页内容?
字节王德发
python beautifulsoup
在当今这个信息爆炸的时代,网络上有大量的数据等待我们去挖掘。如何从网页中提取我们需要的信息呢?使用Python的BeautifulSoup库,能够让这一过程变得简单而高效!接下来,我将带你走进BeautifulSoup的世界,教你如何进行网页解析。BeautifulSoup是什么?BeautifulSoup是一个Python库,专门用于从HTML和XML文件中提取数据。它能够将复杂的网页结构转化为
深入解析 Umi-OCR:高效的免费开源 OCR 文字识别工具
萧鼎
python基础到进阶教程 ocr python Umi-OCR
1.Umi-OCR简介1.1什么是Umi-OCR?Umi-OCR是一款开源、免费、支持离线使用的光学字符识别(OCR)工具,基于PaddleOCR和Tesseract-OCR,能够高效识别图片中的文字,尤其适用于批量截图文字提取、PDF文字识别、手写体识别等应用场景。它具备轻量级、易用、支持多种格式等特点,在文字识别任务中表现优异。1.2Umi-OCR的核心特点完全免费开源:Umi-OCR在Git
黑马程序员瑞吉外卖Day6小程序空白无显示
Lkkkkkkkcy
Java学习 java 微信小程序 前端
做项目时出现问题之druid连接池报错报错discardlongtimenonereceivedconnection.,jdbcUrl:jdbc:mysql://localhost:3306/sky_take_out?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=c
北京大学DeepSeek课程1《DeepSeek与AIGC应用》
daly520
AIGC 人工智能 ai python 深度学习 机器学习
北京大学发布的《DeepSeek与AIGC应用》报告及配套教程,系统介绍了DeepSeek技术特性、AIGC应用场景及实践方法,主要包含以下核心内容:PDF完整版下载北京大学DeepSeek课程《DeepSeek与AIGC应用》下载https://ollama.net.cn/deepseek/14.html一、DeepSeek-R1模型的技术解析1.模型特性与优势DeepSeek-R1是一款专注于
提高SQL查询性能的7个法宝
傻儿哥
ORACLE sql 数据库 报表 sql server sybase 存储
【IT168专稿】每个数据库平台上的SQL开发人员都是在困难中求得生存,我们总是一次又一次犯同样的错误,这是因为数据库领域还相对不成熟,是的,每个数据库厂商都在做着各种不同的努力,但作为开发人员仍然要克服各种问题,无论是在SQLServer,Oracle,DB2,Sybase,MySQL数据库,还是其它关系数据库平台上编写SQL代码,并发性、资源管理、空间管理和SQL运行速度总是困扰着开发人员。遗
0基础学前端---品优购项目Day14
学代码的小前端
0基础学前端 javascript 前端 html css
0基础学前端—品优购项目Day14视频参考:B站Pink老师本节重点:all项目链接:完整的项目已放到品优购完整项目大家可以自行下载强调内容这里主要强调两个知识点:(1)网站TDK三个标签SEO优化(2)logoSEO优化网站TDK三个标签SEO优化T:title网站名(产品名)网站的介绍D:网站是做什么的K:关键字6~8个最好logoSEO优化(1)logo里面首先放一个h1标签,目的是为了提权
Manus:中国AI创新力,开启通用智能体的新时代
YuKeeHgg
Manus 人工智能 Manus
更多精彩内容可点击「华彬智融知识数据库」免费解锁~2025年3月6日,中国科技领域迎来里程碑式突破——由Monica.im团队研发的全球首款通用AI智能体产品“Manus”正式上线。这款被业界誉为“聪明实习生”的AI助手,凭借其自主执行复杂任务的能力,一夜之间引爆全球科技圈,推动A股AI相关板块大涨,软件ETF单日涨幅超3%。Manus的诞生不仅刷新了AI技术应用的高度,更标志着中国团队在智能体(
9.1 shell文本处理
Qiu_SaMa
Linux Shell的学习 linux vim
通常shell脚本最大的用途就在于解析和显示文本文件中的数据,比如日志文件和错误文件。Linux环境包含了两个非常有用的工具:sed和gawk,两者都能够在shell脚本中处理文本数据。1.sed编辑器sed编辑器被称为流编辑器(streameditor),和普通的交互式文本编辑器恰好相反。在交互式文本编辑器中(如vim),可以用键盘命令来交互式地插入、删除或替换数据中的文本。流编辑器则会在编辑器
Stable Diffusion模型Pony系列模型深度解析
Liudef06
Stable Diffusion 人工智能 人工智能作画 stable diffusion AI作画
StableDiffusion模型Pony系列模型深度解析一、技术架构与核心特性基于SDXL的深度优化Pony系列模型以SDXL为基础框架,通过针对二次元/动漫风格的微调,强化了在该领域的生成能力,同时保留了对写实场景的兼容性。其训练数据特别侧重于人物结构、动态姿势和风格化渲染,尤其在处理复杂肢体动作(如手部细节)方面表现出色。训练策略:采用混合精度训练(fp16/bf16)和分层权重调整技术
零基础CMake学习笔记
天鹅打架了
C/C++编程 CMake
零基础CMake学习笔记1.名词解释makecmakeMakefileCMakeLists.txt2.CMake语法介绍2.1常用指令2.1.1project2.1.2set2.1.3message2.1.4add_executable2.1.5aux_source_directory2.1.6include_directories2.1.7add_definitions2.1.8add_subd
Spring 集成事务管理详解:银行转账示例
阿绵
后端 spring java 后端 事务管理
1.前言在JavaEE开发中,数据库事务是保证数据一致性的重要机制。Spring提供了强大的事务管理功能,允许开发者通过声明式事务(基于注解)或编程式事务(手动管理)来控制事务。本文介绍如何在原始Spring框架(非SpringBoot)中集成事务管理,包括配置步骤和代码示例本代码示例版本要求:Java17+Spring6+2.事务管理的基本概念2.1什么是事务?事务(Transaction)是一
Python高级之操作Mysql
_AndyLau
python mysql adb
Python高级文章目录Python高级python操作数据库mysql-connectordemo_mysql_test.py:pyMysqlpython操作数据库mysql-connector本章节为大家介绍使用mysql-connector来连接使用MySQL,mysql-connector是MySQL官方提供的驱动器。可以使用pip命令来安装mysql-connector:python-m
解决安装PyMuPDF(也被称为fitz库)的问题(可成功安装且使用)
汐ya~
python pdf 安装
解决安装PyMuPDF(也被称为fitz库)的问题(可成功安装且使用)安装方法:一些安装时报错的原因解析:报错1:报错2:报错3-无效的分发包警告:报错4:使用实例在使用PyMuPDF发现直接pipinstallPyMuPDF会安装失败或者安装后无法使用安装方法:1.在https://pypi.org/project/PyMuPDF/#files查找到适合自己电脑python版本的.whl文件2.
Milvus 数据批量导入实战:Python代码解析
修破立生
Milvus milvus python 人工智能
1引言在处理大规模数据的存储和检索时,向量数据库逐渐成为一种热门的解决方案。Milvus作为一款高性能的向量数据库,在人工智能、机器学习等领域有着广泛的应用。本文将介绍如何使用Python代码将数据批量导入到Milvus数据库中,通过实际的代码示例来帮助大家理解导入过程和相关的技术要点。2代码功能概述我们的代码主要实现了从本地文件读取数据,并将其批量导入到Milvus数据库的功能。代码涉及到命令行
python如何爬取实时人流量_使用python爬取微信宜出行人流量数据
张衍军
python如何爬取实时人流量
代码地址:https://liujiao111.github.io/2019/06/18/easygo/工具介绍:该工具基于微信中的宜出行提供的数据接口进行爬取,能够爬取一定范围内的当前时间点的人流量数据。环境:windowspython3+安装第三方包:缺啥安装啥使用指南:申请多个qq号,并将qq号放入当前目录下的qqlist.py文件中,格式如下:qq_list=[["11111111","1
英伟达常见产品使用场景对比说明
放羊郎
人工智能技术 项目方案 人工智能 人工智能 深度学习 机器学习 英伟达 训练芯片
产品型号显存容量显存带宽价格(人民币)适用场景模型性能对比数据中心与AI计算H100(SXM)80GBHBM33TB/s未公开(企业级)超大规模AI训练(千亿参数)、HPC比A100性能提升3-6倍(BERT训练),FP8精度加速显著H800(PCIe)80GBHBM2e600GB/s未公开(受管制)中等规模AI训练/推理,支持分批处理带宽为H100的1/5,训练吞吐量降低约40%A100(PCI
QEMU 探索旅程——编译
sunqian666888
qemu qemu编译
QUMU官方介绍ARMSystememulator13.5ARMSystememulator23Usetheexecutableqemu-system-armtosimulateaARMmachine.TheARMIntegrator/CPboardisemulatedwiththefollowingdevices:45-ARM926E,ARM1026E,ARM946E,ARM1136orCort
PHP反序列化漏洞POP链详解 - Yii框架案例分析 (②)
恩师小迪
android 前端 javascript
POP链的第二条路:从Faker\Generator开始现在,让我们一步步解析这条攻击链。我们将从Faker\Generator类的__call魔术方法开始,追踪到最终执行危险函数的地方。第一步:触发__call魔术方法在PHP中,当你尝试调用一个对象中不存在的方法时,如果该对象定义了__call魔术方法,PHP会自动调用它。假设我们有一个Faker\Generator对象:$generator=
汽车电子软件开发需知
嵌入式知行
车载通信 汽车 嵌入式硬件 单片机 c++
目录一、嵌入式1.1什么是嵌入式系统1.2什么是汽车ECU1.3如何了解一款MCU1.4谈谈代码静态分析二、汽车软件2.1什么是“域控制器”2.2为什么是ARXML2.3SOA:面向服务的架构2.4下一代的EEA(电子电气架构)2.5ADAS的八大系统(汽车高级辅助驾驶系统)三、流程类3.1什么是软件定义汽车3.2汽车软件开发V模型3.3谈谈ASPICE3.4ISO262623.5功能安全一、嵌入
预算有限下独立站建站的高性价比客服系统之选:GullChat 引领新潮流
gullchat
即时聊天 独立站客服 gullchat 网站客服 在线客服系统 实时聊天
在独立站蓬勃发展的当下,对于预算有限的建站者而言,每一笔资金的使用都需精打细算。客服系统作为连接客户的关键纽带,其选择直接影响着客户体验和运营成本。如何在有限预算内挑选到高性价比的客服系统,成为众多建站者亟待解决的难题。而GullChat凭借其独特的优势,为预算有限的独立站带来了新的曙光。一、精准聚焦核心功能,避免功能冗余浪费对于预算有限的独立站来说,明确自身核心功能需求是首要任务。实时聊天和智能
linux检查内存
Rain_Rong
linux adb 运维
安装smemsudoyuminstallepel-releasesudoyuminstallsmemsmem使用https://blog.csdn.net/zdy0_2004/article/details/50412760查询用户使用smem-uUser:表示拥有相关进程的用户账户名。例如,root表示该进程由超级用户root运行,mysql表示由mysql用户运行的进程等。Count:指以该用
四足机器人机架设计新突破!如何让AI机器人“站稳脚跟”?
CodePatentMaster
宇树机器人 人工智能 机器人 科技
核心价值:通过创新的机架形状设计,显著提升四足机器人结构稳定性与运动适应性,为AI机器人提供高效承载平台。(申请人:杭州宇树科技有限公司;申请号:201730334315.4)一、专利技术深度解析技术背景传统四足机器人机架常面临结构笨重、负载分布不均、运动灵活性不足等问题,影响复杂环境下的作业效率。该专利通过优化机架形状设计,解决了机器人轻量化与高强度之间的矛盾,使其更适应动态场景需求。核心创新点
每日一题之数字诗意
Ace'
c++ 算法 开发语言
题描述在诗人的眼中,数字是生活的韵律,也是诗意的表达。小蓝,当代顶级诗人与数学家,被赋予了"数学诗人"的美誉。他擅长将冰冷的数字与抽象的诗意相融合,并用优雅的文字将数学之美展现于纸上。某日,小蓝静坐书桌前,目光所及,展现着nn个数字,它们依次为a1,a2,…,an,熠熠生辉。小蓝悟到,如果一个数能够以若干个(至少两个)连续的正整数相加表示,那么它就蕴含诗意。例如,数字6就蕴含诗意,因为它可以表示为
@NotEmpty、@NotBlank等注解的正确使用 @Validated和@Valid的区别 解决@NotBlank等注解不生效的问题 使用BindingResult进行接口请求参数的统一校验
互联网全栈开发实战
后端开发技术的解决方法 spring spring boot 后端 java java-ee
文章目录1.问题说明2.配置依赖3.编写注解的bean4.常用注解说明4.1空检查4.2布尔检查4.3长度检查4.4日期检查4.5数值检查5.编写controller5.1@Validated和@Valid区别6.解决@NotBlank等注解不生效的问题7.其他注解说明1.问题说明服务端通常将controller层作为调用的第一层,因而参数校验常常在这里完成,比如非空校验、类型校验等,如下登录接口
【云原生之Docker实战】使用Docker部署Taskover开源个人任务管理工具
江湖有缘
Docker部署项目实战合集 云原生 docker 开源 Taskover 任务管理工具
【云原生之Docker实战】使用Docker部署Taskover开源个人任务管理工具一、Taskover介绍1.Taskover简介2.Taskover功能二、检查本地docker环境1.检查系统版本2.检查docker版本3.检查docker状态4.检查dockercompose版本三、下载Taskover镜像四、部署Taskover应用1.创建安装目录2.编辑docker-compose.ya
【云原生之Docker实战】使用Docker部署Traefik开源边缘路由器
江湖有缘
docker 云原生 开源
【云原生之Docker实战】使用Docker部署Traefik开源边缘路由器一、Traefik介绍1.Traefik简介2.Traefik特点二、检查宿主机系统版本三、检查本地docker环境1.检查docker服务状态2.检查docker配置信息3.开启IPv4forwarding4.检查Docker版本四、安装docker-compose1.下载docker-compose二进制包2.给文件增
jQuery 跨域访问的三种方式 No 'Access-Control-Allow-Origin' header is present on the reque
qiaolevip
每天进步一点点 学习永无止境 跨域 众观千象
XMLHttpRequest cannot load http://v.xxx.com. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63342' is therefore not allowed access. test.html:1
mysql 分区查询优化
annan211
java 分区 优化 mysql
分区查询优化
引入分区可以给查询带来一定的优势,但同时也会引入一些bug.
分区最大的优点就是优化器可以根据分区函数来过滤掉一些分区,通过分区过滤可以让查询扫描更少的数据。
所以,对于访问分区表来说,很重要的一点是要在where 条件中带入分区,让优化器过滤掉无需访问的分区。
可以通过查看explain执行计划,是否携带 partitions
MYSQL存储过程中使用游标
chicony
Mysql存储过程
DELIMITER $$
DROP PROCEDURE IF EXISTS getUserInfo $$
CREATE PROCEDURE getUserInfo(in date_day datetime)-- -- 实例-- 存储过程名为:getUserInfo-- 参数为:date_day日期格式:2008-03-08-- BEGINdecla
mysql 和 sqlite 区别
Array_06
sqlite
转载:
http://www.cnblogs.com/ygm900/p/3460663.html
mysql 和 sqlite 区别
SQLITE是单机数据库。功能简约,小型化,追求最大磁盘效率
MYSQL是完善的服务器数据库。功能全面,综合化,追求最大并发效率
MYSQL、Sybase、Oracle等这些都是试用于服务器数据量大功能多需要安装,例如网站访问量比较大的。而sq
pinyin4j使用
oloz
pinyin4j
首先需要pinyin4j的jar包支持;jar包已上传至附件内
方法一:把汉字转换为拼音;例如:编程转换后则为biancheng
/**
* 将汉字转换为全拼
* @param src 你的需要转换的汉字
* @param isUPPERCASE 是否转换为大写的拼音; true:转换为大写;fal
微博发送私信
随意而生
微博
在前面文章中说了如和获取登陆时候所需要的cookie,现在只要拿到最后登陆所需要的cookie,然后抓包分析一下微博私信发送界面
http://weibo.com/message/history?uid=****&name=****
可以发现其发送提交的Post请求和其中的数据,
让后用程序模拟发送POST请求中的数据,带着cookie发送到私信的接入口,就可以实现发私信的功能了。
jsp
香水浓
jsp
JSP初始化
容器载入JSP文件后,它会在为请求提供任何服务前调用jspInit()方法。如果您需要执行自定义的JSP初始化任务,复写jspInit()方法就行了
JSP执行
这一阶段描述了JSP生命周期中一切与请求相关的交互行为,直到被销毁。
当JSP网页完成初始化后
在 Windows 上安装 SVN Subversion 服务端
AdyZhang
SVN
在 Windows 上安装 SVN Subversion 服务端2009-09-16高宏伟哈尔滨市道里区通达街291号
最佳阅读效果请访问原地址:http://blog.donews.com/dukejoe/archive/2009/09/16/1560917.aspx
现在的Subversion已经足够稳定,而且已经进入了它的黄金时段。我们看到大量的项目都在使
android开发中如何使用 alertDialog从listView中删除数据?
aijuans
android
我现在使用listView展示了很多的配置信息,我现在想在点击其中一条的时候填出 alertDialog,点击确认后就删除该条数据,( ArrayAdapter ,ArrayList,listView 全部删除),我知道在 下面的onItemLongClick 方法中 参数 arg2 是选中的序号,但是我不知道如何继续处理下去 1 2 3
jdk-6u26-linux-x64.bin 安装
baalwolf
linux
1.上传安装文件(jdk-6u26-linux-x64.bin)
2.修改权限
[root@localhost ~]# ls -l /usr/local/jdk-6u26-linux-x64.bin
3.执行安装文件
[root@localhost ~]# cd /usr/local
[root@localhost local]# ./jdk-6u26-linux-x64.bin&nbs
MongoDB经典面试题集锦
BigBird2012
mongodb
1.什么是NoSQL数据库?NoSQL和RDBMS有什么区别?在哪些情况下使用和不使用NoSQL数据库?
NoSQL是非关系型数据库,NoSQL = Not Only SQL。
关系型数据库采用的结构化的数据,NoSQL采用的是键值对的方式存储数据。
在处理非结构化/半结构化的大数据时;在水平方向上进行扩展时;随时应对动态增加的数据项时可以优先考虑使用NoSQL数据库。
在考虑数据库的成熟
JavaScript异步编程Promise模式的6个特性
bijian1013
JavaScript Promise
Promise是一个非常有价值的构造器,能够帮助你避免使用镶套匿名方法,而使用更具有可读性的方式组装异步代码。这里我们将介绍6个最简单的特性。
在我们开始正式介绍之前,我们想看看Javascript Promise的样子:
var p = new Promise(function(r
[Zookeeper学习笔记之八]Zookeeper源代码分析之Zookeeper.ZKWatchManager
bit1129
zookeeper
ClientWatchManager接口
//接口的唯一方法materialize用于确定那些Watcher需要被通知
//确定Watcher需要三方面的因素1.事件状态 2.事件类型 3.znode的path
public interface ClientWatchManager {
/**
* Return a set of watchers that should
【Scala十五】Scala核心九:隐式转换之二
bit1129
scala
隐式转换存在的必要性,
在Java Swing中,按钮点击事件的处理,转换为Scala的的写法如下:
val button = new JButton
button.addActionListener(
new ActionListener {
def actionPerformed(event: ActionEvent) {
Android JSON数据的解析与封装小Demo
ronin47
转自:http://www.open-open.com/lib/view/open1420529336406.html
package com.example.jsondemo;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
impor
[设计]字体创意设计方法谈
brotherlamp
UI ui自学 ui视频 ui教程 ui资料
从古至今,文字在我们的生活中是必不可少的事物,我们不能想象没有文字的世界将会是怎样。在平面设计中,UI设计师在文字上所花的心思和功夫最多,因为文字能直观地表达UI设计师所的意念。在文字上的创造设计,直接反映出平面作品的主题。
如设计一幅戴尔笔记本电脑的广告海报,假设海报上没有出现“戴尔”两个文字,即使放上所有戴尔笔记本电脑的图片都不能让人们得知这些电脑是什么品牌。只要写上“戴尔笔
单调队列-用一个长度为k的窗在整数数列上移动,求窗里面所包含的数的最大值
bylijinnan
java 算法 面试题
import java.util.LinkedList;
/*
单调队列 滑动窗口
单调队列是这样的一个队列:队列里面的元素是有序的,是递增或者递减
题目:给定一个长度为N的整数数列a(i),i=0,1,...,N-1和窗长度k.
要求:f(i) = max{a(i-k+1),a(i-k+2),..., a(i)},i = 0,1,...,N-1
问题的另一种描述就
struts2处理一个form多个submit
chiangfai
struts2
web应用中,为完成不同工作,一个jsp的form标签可能有多个submit。如下代码:
<s:form action="submit" method="post" namespace="/my">
<s:textfield name="msg" label="叙述:">
shell查找上个月,陷阱及野路子
chenchao051
shell
date -d "-1 month" +%F
以上这段代码,假如在2012/10/31执行,结果并不会出现你预计的9月份,而是会出现八月份,原因是10月份有31天,9月份30天,所以-1 month在10月份看来要减去31天,所以直接到了8月31日这天,这不靠谱。
野路子解决:假设当天日期大于15号
mysql导出数据中文乱码问题
daizj
mysql 中文乱码 导数据
解决mysql导入导出数据乱码问题方法:
1、进入mysql,通过如下命令查看数据库编码方式:
mysql> show variables like 'character_set_%';
+--------------------------+----------------------------------------+
| Variable_name&nbs
SAE部署Smarty出现:Uncaught exception 'SmartyException' with message 'unable to write
dcj3sjt126com
PHP smarty sae
对于SAE出现的问题:Uncaught exception 'SmartyException' with message 'unable to write file...。
官方给出了详细的FAQ:http://sae.sina.com.cn/?m=faqs&catId=11#show_213
解决方案为:
01
$path
《教父》系列台词
dcj3sjt126com
Your love is also your weak point.
你的所爱同时也是你的弱点。
If anything in this life is certain, if history has taught us anything, it is
that you can kill anyone.
不顾家的人永远不可能成为一个真正的男人。 &
mongodb安装与使用
dyy_gusi
mongo
一.MongoDB安装和启动,widndows和linux基本相同
1.下载数据库,
linux:mongodb-linux-x86_64-ubuntu1404-3.0.3.tgz
2.解压文件,并且放置到合适的位置
tar -vxf mongodb-linux-x86_64-ubun
Git排除目录
geeksun
git
在Git的版本控制中,可能有些文件是不需要加入控制的,那我们在提交代码时就需要忽略这些文件,下面讲讲应该怎么给Git配置一些忽略规则。
有三种方法可以忽略掉这些文件,这三种方法都能达到目的,只不过适用情景不一样。
1. 针对单一工程排除文件
这种方式会让这个工程的所有修改者在克隆代码的同时,也能克隆到过滤规则,而不用自己再写一份,这就能保证所有修改者应用的都是同一
Ubuntu 创建开机自启动脚本的方法
hongtoushizi
ubuntu
转载自: http://rongjih.blog.163.com/blog/static/33574461201111504843245/
Ubuntu 创建开机自启动脚本的步骤如下:
1) 将你的启动脚本复制到 /etc/init.d目录下 以下假设你的脚本文件名为 test。
2) 设置脚本文件的权限 $ sudo chmod 755
第八章 流量复制/AB测试/协程
jinnianshilongnian
nginx lua coroutine
流量复制
在实际开发中经常涉及到项目的升级,而该升级不能简单的上线就完事了,需要验证该升级是否兼容老的上线,因此可能需要并行运行两个项目一段时间进行数据比对和校验,待没问题后再进行上线。这其实就需要进行流量复制,把流量复制到其他服务器上,一种方式是使用如tcpcopy引流;另外我们还可以使用nginx的HttpLuaModule模块中的ngx.location.capture_multi进行并发
电商系统商品表设计
lkl
DROP TABLE IF EXISTS `category`; -- 类目表
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `category` (
`id` int(11) NOT NUL
修改phpMyAdmin导入SQL文件的大小限制
pda158
sql mysql
用phpMyAdmin导入mysql数据库时,我的10M的
数据库不能导入,提示mysql数据库最大只能导入2M。
phpMyAdmin数据库导入出错: You probably tried to upload too large file. Please refer to documentation for ways to workaround this limit.
Tomcat性能调优方案
Sobfist
apache jvm tomcat 应用服务器
一、操作系统调优
对于操作系统优化来说,是尽可能的增大可使用的内存容量、提高CPU的频率,保证文件系统的读写速率等。经过压力测试验证,在并发连接很多的情况下,CPU的处理能力越强,系统运行速度越快。。
【适用场景】 任何项目。
二、Java虚拟机调优
应该选择SUN的JVM,在满足项目需要的前提下,尽量选用版本较高的JVM,一般来说高版本产品在速度和效率上比低版本会有改进。
J
SQLServer学习笔记
vipbooks
数据结构 xml
1、create database school 创建数据库school
2、drop database school 删除数据库school
3、use school 连接到school数据库,使其成为当前数据库
4、create table class(classID int primary key identity not null)
创建一个名为class的表,其有一