Ubiquitous Design Pattern in Android development-dynamic proxy pattern

Source: Internet
Author: User

Ubiquitous Design Pattern in Android development-dynamic proxy pattern

Continue to update the design pattern series. The main reason for writing this pattern is that the dynamic proxy code has been seen recently.
Let's review the first five modes:
-Ubiquitous Design Pattern in Android development-Singleton pattern
-Ubiquitous Design Pattern in Android development-Builder Pattern
-Ubiquitous Design Pattern in Android development-Observer Pattern
-Ubiquitous Design Pattern in Android development-prototype Pattern
-Ubiquitous Design Pattern in Android development-Rule Pattern

The dynamic proxy mode can be seen everywhere in Java WEB applications, especially the dynamic proxy is widely used in the Spring framework. It is the most important design mode, it is also one of the most difficult to understand design patterns.

So what is dynamic proxy?

A dynamic proxy is a proxy that does not exist before the program runs and is dynamically generated by the program.

Currently, there are a variety of network request libraries. Square's OkHttp is a perfect network request library, and it encapsulates a layer of Dynamic Fit library, it provides a shortcut for convenient and convenient calling of Restful APIs. If you have used Retrofit, you will not forget that there is such a process:

First, define an interface that defines the specific methods of network requests, and configure host, header, params, and other information through annotations.

Create a new fit object to generate a custom interface object.

Call a specific method through an interface object to complete the request.

Like this:

> listRepos(@Path("user") String user);}" data-snippet-id="ext.fadc3883ecfd2cd1a1ca67e15e7b1971" data-snippet-saved="false" data-csrftoken="5VgX1Wh4-W-l4cPYta7C6PsnrxDn_HUux6Fk">public interface GitHubService {  @GET("users/{user}/repos")  Call
  
   > listRepos(@Path("user") String user);}
  
Retrofit retrofit = new Retrofit.Builder()    .baseUrl("https://api.github.com")    .build();GitHubService service = retrofit.create(GitHubService.class);
> repos = service.listRepos("octocat");" data-snippet-id="ext.ee6b799b6e05337f344653d3f6028237" data-snippet-saved="false" data-csrftoken="zatspdc2-6xr9Qf-RbSgSei_XQsqIqeqXvQQ">Call
  
   > repos = service.listRepos("octocat");
  

Have you ever wondered how the GitHubService interface instance is generated? What is the internal function of the optimize fit. create method. Yes, the answer is dynamic proxy. This object is a proxy object generated during the running of the program.

Although dynamic proxies are widely used in Java WEB, dynamic proxies are carefully considered on the client due to performance issues. However, once dynamic proxies are used properly, it will produce different results, such as the wide fit library. Next, we will implement the simplest version of Retrofit. Let's take a look at the principle of dynamic proxy. Because it is a simple version, there is still a gap between many things and Retrofit. Naturally, it is not as convenient as Retrofit. This is just enough to ignore it. Let's take the above example as an example:

First of all, our request is asynchronous, so we use void to return the value, and add a callback parameter. The final parameter is the callback.

 {    void onSuccess(Object t);    void onFailed(Exception e);}" data-snippet-id="ext.a886f274abbdc51fa06b7d1abed39036" data-snippet-saved="false" data-csrftoken="notDIIJF-5EKuT6X6LWWipbRR2DHvKJcZYxM">public interface Callback
  
    {    void onSuccess(Object t);    void onFailed(Exception e);}
  

The final interface definition will look like this.

> Callback);/*** specify that the last parameter is callback */} "data-snippet-id =" ext. f115dcec337f47ddaaf65522ab40a2e0 "data-snippet-saved =" false "data-csrftoken =" hOCzSeOZ-2RNrlcsbRh9aW4trRlUk_l6C1D4 ">Public interface GithubService {@ GET ("users/{user}/repos") void listRepos (@ Path ("user") String user, Callback
  
   
> Callback);/*** specify that the last parameter is callback */}
  

Two annotations are used: Method annotation and parameter annotation.

@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD})public @interface GET {    String value() default "";}
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.PARAMETER)public @interface Path {    String value();}

The Repo object class is automatically generated based on json using GsonFormat.

Then we compile the compile fit class. This class should be in the builder mode. You can set baseUrl to ignore all other parameters. There is also a create method, the prototype is as follows:

public class Retrofit {    private String baseUrl;    private Retrofit(Builder builder) {        this.baseUrl = builder.baseUrl;    }    public 
  
    T create(Class
   
     clazz) {        return null    }    static class Builder {        private String baseUrl;        Builder baseUrl(String host) {            this.baseUrl = host;            return this;        }        Retrofit build() {            return new Retrofit(this);        }    }}
   
  

The most important thing is the implementation of the create method. The principle is to get the last parameter, that is, the callback, get the Annotation on the method, get the specific value, then get other parameters besides the callback, and get the Annotation on the parameter, then obtain the corresponding value based on the annotation and the original parameter value. Replace the value of the annotation in the method. Use OkHttp to construct a request. After the request is complete, the result is parsed as the type in the callback. The entire process is as follows:

Public
  
   
T create (Class
   
    
Clazz) {/*** go to the cache */Object o = serviceMap. get (clazz);/*** construct Proxy object if no result is obtained */if (o = null) {o = (T) Proxy. newProxyInstance (invalid fit. class. getClassLoader (), new Class [] {clazz}, new InvocationHandler () {@ Override public Object invoke (Object proxy, Method method, Object [] args) throws Throwable {final Callback
    Callback = (Callback
    ) Args [args. length-1]; final GET get = method. getAnnotation (GET. class); if (get! = Null) {/*** GET the value of the get annotation */String getValue = GET. value (); System. out. println (getValue);/*** obtain the Annotation on all parameters */Annotation [] [] methodParameterAnnotationArrays = method. getParameterAnnotations (); if (methodParameterAnnotationArrays! = Null) {int count = methodParameterAnnotationArrays. length; for (int I = 0; I <count; I ++) {/*** obtain the Annotation on a single parameter */Annotation [] methodParameterAnnotations = methodParameterAnnotationArrays [I]; if (methodParameterAnnotations! = Null) {for (Annotation methodParameterAnnotation: methodParameterAnnotations) {/*** if it is a Path Annotation */if (methodParameterAnnotation instanceof Path) {/*** obtain the value of path annotation */Path path = (Path) methodParameterAnnotation; String pathValue = path. value (); System. out. println (pathValue);/*** this is the value of the corresponding parameter */System. out. println (args [I]); Request. builder builder = new Request. builder ();/*** use the path annotation to replace the value in the get Annotation with the parameter value */String result = getValue. replaceAll ("\ {" + pathValue + "\}", (String) args [I]); System. out. println (result);/*** start to construct the Request */request Request = builder. get (). url (baseUrl + "/" + result ). build (); okHttpClient. newCall (request ). enqueue (new okhttp3.Callback () {@ Override public void onFailure (Call call, IOException e) {/*** method of callback failure upon failure */callback. onFailed (e) ;}@ Override public void onResponse (Call call, Response response) throws IOException {if (response. isSuccessful () {/*** request successful */String body = response. body (). string ();/*** use fastjson to convert zhuan */Type type = callback. getClass (). getGenericInterfaces () [0]; Object o1 = JSON. parse (body);/*** callback successful */callback. onSuccess (o1) ;}}}}}}}return null ;}});/*** throw it to the cache */serviceMap. put (clazz, o);} return (T) o ;}
   
  

Then we can make the call according to fit.

Retrofit retrofit = new Retrofit.Builder()        .baseUrl("https://api.github.com")        .build();GithubService githubService = retrofit.create(GithubService.class);githubService.listRepos("lizhangqu", new Callback
  
   >() {    @Override    public void onSuccess(Object t) {        System.out.println(t);    }    @Override    public void onFailed(Exception e) {    }});
  

This is only one of the simplest modules of Alibaba fit. If you are interested in other content, you can read the source code of Alibaba fit.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.