Agent a.

Agent is easy to understand the word, just like our familiar act as purchasing agency, we don’t directly and businesses to buy goods, but by the middle kindly help us to buy, the dealer here is similar to the agent, the role of middlemen is certainly want to earn price difference, of course, ha ha, in Java agent according to create opportunity and way are different, can be divided into two kinds: Static and dynamic proxies.

1. Static proxy

To use static proxies, the proxyed object and the proxy object need to have a common parent class or implement the same interface. For example, create a random class for what we call the proxyed object, create a PrintInfoIter interface, and then create the Student class to implement it as described above:

interface PrintInfoIter {
    fun printInfo()
}

class Student :PrintInfoIter{
    override fun printInfo(){
        Log.e("proxy","----printInfo")
    }
}
Copy the code

Then create the proxy object class, which also implements the PrintInfoIter interface, as follows:

class StudentImpProxy(var infoIter: PrintInfoIter) : PrintInfoIter { private var printInfoIter: PrintInfoIter? = null init { this.printInfoIter = infoIter } override fun printInfo() { printInfoIter? . Let {Log. E (" proxy ", "-- -- -- -- -- -- -- -- call printInfo before"). It printInfo () the e (" proxy ", "-- -- -- -- -- -- -- -- call printInfo after")}}}Copy the code

The usage is as follows:

/ / static agent val studentImpProxy = studentImpProxy (Student ()) studentImpProxy. PrintInfo ()Copy the code

Results:

The effect of static agent is on the premise of not modified by the proxy class code, to extend function, defect is clear, need the proxy class and proxy class all have a common parent class or implement the same interface, is a static, personal understanding is code has been written before the program is run by non dynamically generated proxy function.

2. Dynamic proxy

Dynamic Proxy mainly relies on Proxy and InvocationHandler to complete Proxy work, and creates Proxy class through Proxy newProxyInstance method:

//interfaces: an array of interfaces implemented by objects //h: Public static Object newProxyInstance(ClassLoader, Class<? >[] interfaces, InvocationHandler h)Copy the code

How do you use it? Again, see how the dynamic proxy approach works:

/** * class StudentProxy: InvocationHandler {var obj: Any? = null fun newProxyInstance(obj: Any?) : Any { this.obj = obj return Proxy.newProxyInstance(obj!! .javaClass.classLoader, obj.javaClass.interfaces, this) } override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any {var result: Any? = null log. e("proxy","-------- before calling ${method} ") var argsTemp: Array<out Any>? = arrayOf() args?.let { if(args.isNotEmpty()) argsTemp = args } result = if(! argsTemp.isNullOrEmpty()){ method? .invoke(obj,argsTemp) }else{ method? Invoke (obj)} the e (" proxy ", "-- -- -- -- -- -- -- -- after the call to ${method}") return the result? : Any() } }Copy the code

Use:

/ / dynamic proxy val studentProxy = studentProxy () val printInfoIter = studentProxy. NewProxyInstance (Student ()) as printInfoIter printInfoIter.printInfo()Copy the code

Results:

Dynamic proxy does not need to implement the same interface or common parent class as the propped object, which is relatively flexible, but it is also based on interface proxy. In addition, JDK dynamic proxy is supported by Java native, and does not require any external dependencies.

The Retrofit.

Retrofit is the mainstream web framework for Android development today, or a library that encapsulates all aspects of a web request, as it still uses OKHTTP to send web requests underneath. Let’s take a look at the source code for the request process below.

1.retrofit.create

When we use Retrofit for network requests, we typically need a class that sets the parameters of the interface, including the request type, parameters, headers, etc., and then obtains an instance of that class via Retrofit.create, which looks something like this:

val apiService = retrofit.create(apiClass)
Copy the code

Let’s take a look at what Retrofit.create does:

public <T> T create(final Class<T> service) { validateServiceInterface(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. if  (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } // return loadServiceMethod(method).invoke(args! = null ? args : emptyArgs); }}); }Copy the code

Invoke loadServiceMethod(Method).invoke LoadServiceMethod is a class that resolves the various parameters of a request.

2.ServiceMethod

LoadServiceMethod is of ServiceMethod type and the code is as follows:

ServiceMethod<? > loadServiceMethod(Method method) { ServiceMethod<? > result = serviceMethodCache.get(method); if (result ! = null) return result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { result = ServiceMethod.parseAnnotations(this, method); serviceMethodCache.put(method, result); } } return result; }Copy the code

Annotations () ServiceMethod is an abstract class, and its implementation is HttpServiceMethod.

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory) { boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction; boolean continuationWantsResponse = false; boolean continuationBodyNullable = false; Annotations [] Annotations = method.getanannotations (); Type adapterType; / / Kotlin suspend the processing of the if (isKotlinSuspendFunction) {Type [] parameterTypes = method. The getGenericParameterTypes (); Type responseType = Utils.getParameterLowerBound(0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]); adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType); annotations = SkipCallbackExecutorImpl.ensurePresent(annotations); } else { adapterType = method.getGenericReturnType(); } // According to the addCallAdapterFactory type set, CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations); Type responseType = callAdapter.responseType(); // Create different response converters according to the addConverterFactory type set. ResponseBody, ResponseT> responseConverter = responateresponSeconverter (retrofit, method) responseType); okhttp3.Call.Factory callFactory = retrofit.callFactory; // Create different HttpServiceMethod if (! isKotlinSuspendFunction) { return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); } else if (continuationWantsResponse) { //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object. return  (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>(requestFactory, callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter); } else { //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object. return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory, callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter, continuationBodyNullable); }}Copy the code

CallAdapter transforms okHttp3. call into retrofit2. call, or Observable for RxJava, which can be used to initiate network requests. Calladapter object can be set through addCallAdapterFactory method, do not use the system default DefaultCallAdapterFactory Settings, such as if we use rxjava, usually set up RxJava2CallAdapter, RxJava2CallAdapter

Final class RxJava2CallAdapter<R> implements CallAdapter<R, Object> {private final Type responseType; private final @Nullable Scheduler scheduler; private final boolean isAsync; private final boolean isResult; private final boolean isBody; private final boolean isFlowable; private final boolean isSingle; private final boolean isMaybe; private final boolean isCompletable; RxJava2CallAdapter(Type responseType, @Nullable Scheduler scheduler, boolean isAsync, boolean isResult, boolean isBody, boolean isFlowable, boolean isSingle, boolean isMaybe, boolean isCompletable) { this.responseType = responseType; this.scheduler = scheduler; . } @Override public Type responseType() { return responseType; } @override public Object adapt(Call<R> Call) {responseObservable <Response >> responseObservable = isAsync? new CallEnqueueObservable<>(call) : new CallExecuteObservable<>(call); Observable<? > observable; if (isResult) { observable = new ResultObservable<>(responseObservable); } else if (isBody) { observable = new BodyObservable<>(responseObservable); } else { observable = responseObservable; } return RxJavaPlugins.onAssembly(observable); }}Copy the code

RxJava2CallAdapter implements Retrofit’s CallAdapter interface. Adapt sees two familiar classes, CallEnqueueObservable and CallExecuteObservable. Classes for asynchronous and synchronous network requests, CallEnqueueObservable code:

Final class CallEnqueueObservable<T> extends Observable<Response<T>> {private final Call<T> originalCall; CallEnqueueObservable(Call<T> originalCall) { this.originalCall = originalCall; } @Override protected void subscribeActual(Observer<? super Response<T>> observer) { // Since Call is a one-shot type, clone it for each new observer. Call<T> call = originalCall.clone(); CallCallback<T> callback = new CallCallback<>(call, observer); observer.onSubscribe(callback); if (! Callback.isdisposed ()) {// Send the network request call.enqueue(callback); } } private static final class CallCallback<T> implements Disposable, Callback<T> { private final Call<? > call; private final Observer<? super Response<T>> observer; private volatile boolean disposed; boolean terminated = false; CallCallback(Call<? > call, Observer<? super Response<T>> observer) { this.call = call; this.observer = observer; } @Override public void onResponse(Call<T> call, Response<T> response) { if (disposed) return; try { observer.onNext(response); if (! disposed) { terminated = true; observer.onComplete(); } } catch (Throwable t) { } } @Override public void onFailure(Call<T> call, Throwable t) { } @Override public void dispose() { call.cancel(); }}}Copy the code

The call. Enqueue is essentially an OkHttpCall created in the Invoke method of the HttpServiceMethod class. OkHttpCall encapsulates the okHTTP network request. Also the class in Retrofit that specifically sends network requests:

 @Override final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }
Copy the code

3.OkHttpCall

OkHttpCall is a retrofit library that encapsulates okHTTP network requests. OkHttpCall is a retrofit library that encapsulates okHTTP network requests. OkHttpCall is a retrofit library that encapsulates okHTTP network requests.

Network request process: When the apiService method is called, Retrofit’s Create () generates a Proxy class object through a dynamic Proxy, which is created with proxy.newProxyInstance (), and then uses the ServiceMethod class to parse the annotations and encapsulate the request. The invoke() method is then called to create an OkHttpCall class for sending network requests, and eventually returns either a Call object for making network requests or an Observable for use with RXJava.

In short, Retrofit is an encapsulation of the OKHTTP network framework, which makes it easier to initiate network requests in a few steps. In addition, it can be used with RXJava or Kotlin coroutines to make network requests easier and faster. So far, this article is coming to the end. If there is any help for you, I will be very happy to like and support you!