继续更新设计模式系列。写这个模式的主要原因是近期看到了动态代理的代码。
先来回想一下前5个模式:
- Android开发中无处不在的设计模式——单例模式
- Android开发中无处不在的设计模式——Builder模式
- Android开发中无处不在的设计模式——观察者模式
- Android开发中无处不在的设计模式——原型模式
- Android开发中无处不在的设计模式——策略模式

动态代理模式在Java WEB中的应用简直是随处可见。尤其在Spring框架中大量的用到了动态代理;算是最重要的一个设计模式。也是最难理解的设计模式之中的一个。

那么什么叫动态代理呢

代理类在程序执行前不存在、执行时由程序动态生成的代理方式称为动态代理。

当前的网络请求库多种多样。当中Square公司的OkHttp简直是完美的一个网络请求库,而在其上又封装了一层的Retrofit库,为方便快捷的调用Restful Api提供了一种捷径。假设你用过Retrofit。一定不会忘记有会有这么一个过程:

  • 首先定义一个接口。接口中定义网络请求的详细方法。在方法上通过注解配置host,header。params等信息。

  • 然后新建一个Retrofit对象,通过该对象产生一个你定义的接口对象。

  • 通过接口对象调用详细的方法完毕请求。

就像这样子:


public interface GitHubService {@GET("users/{user}/repos")Call<List<Repo>> listRepos(@Path("user") String user);}

Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.github.com").build();GitHubService service = retrofit.create(GitHubService.class);

Call<List<Repo>> repos = service.listRepos("octocat");

那么你有没有想过一个问题,接口是不能够直接new出来的。GitHubService接口的实例是怎样产生的呢。retrofit.create方法内部究竟做了什么呢。没错。答案就是动态代理。该对象是程序执行期生成的代理对象。

动态代理尽管在Java WEB中大量的用到,可是在client,因为考虑到性能的问题,所以用动态代理都会谨慎考虑,可是,一旦动态代理用的好,就会产生不一样的效果,就比方这个Retrofit库。以下,我们实现一个Retrofit的最最简易的版本号。过一下动态代理的原理。因为是简易版,所以非常多东西和Retrofit还是有差距的,自然也没有Retrofit那么方便,这点无视就好了。我们就以实现上面那个样例为例:

首先说明一点,我们的请求是异步的,所以返回值我们使用void,添加一个回调的參数,约定最后一个參数是回调。

public interface Callback<T> {void onSuccess(Object t);void onFailed(Exception e);}

终于的接口定义会是这个样子。


public interface GithubService {@GET("users/{user}/repos")void listRepos(@Path("user") String user,Callback<List<Repo>> callback);/*** 约定最后一个參数是callback*/}

用到了两个注解。一个是方法注解,一个是參数注解


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

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

Repo实体类是使用GsonFormat依据json自己主动生成的。

然后我们编写Retrofit类,这个类应该是一个builder模式。里面能够设置baseUrl,姑且忽略其它全部參数。另一个create方法。则原型例如以下:

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

最最关键的内容就是create方法的实现了。原理就是先拿到最后一个參数,也就是回调。再拿到方法上的注解,获得详细的值。然后拿到除了回调之外的其它參数,获得參数上的注解,然后依据注解取得相应的值。还有原来的參数值。将方法上的注解的值中进行替换。使用OkHttp构造请求,请求完毕后依据将结果解析为回调中的类型。整个步骤例如以下

public <T> T create(Class<T> clazz) {/*** 缓存中去*/Object o = serviceMap.get(clazz);/*** 取不到则取构造代理对象*/if (o == null) {o = (T) Proxy.newProxyInstance(Retrofit.class.getClassLoader(), new Class[]{clazz}, new InvocationHandler() {@Overridepublic 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注解的值 */ String getValue = get.value(); System.out.println(getValue); /** * 获得全部參数上的注解 */ Annotation[][] methodParameterAnnotationArrays = method.getParameterAnnotations(); if (methodParameterAnnotationArrays != null) { int count = methodParameterAnnotationArrays.length; for (int i = 0; i < count; i++) { /** * 获得单个參数上的注解 */ Annotation[] methodParameterAnnotations = methodParameterAnnotationArrays[i]; if (methodParameterAnnotations != null) { for (Annotation methodParameterAnnotation : methodParameterAnnotations) { /** * 假设是Path注解 */ if (methodParameterAnnotation instanceof Path) { /** * 取得path注解上的值 */ Path path = (Path) methodParameterAnnotation; String pathValue = path.value(); System.out.println(pathValue); /** * 这是相应的參数的值 */ System.out.println(args[i]); Request.Builder builder = new Request.Builder(); /** * 使用path注解替换get注解中的值为參数值 */ String result = getValue.replaceAll("\\{" + pathValue + "\\}", (String) args[i]); System.out.println(result); /** * 開始构造请求 */ Request request = builder.get() .url(baseUrl + "/" + result) .build(); okHttpClient.newCall(request).enqueue(new okhttp3.Callback() { @Override public void onFailure(Call call, IOException e) { /** * 失败则回调失败的方法 */ callback.onFailed(e); } @Override public void onResponse(Call call, Response response) throws IOException { if (response.isSuccessful()) { /** * 请求成功 */ String body = response.body().string(); /** * 使用fastjson进行zhuan转换 */ Type type = callback.getClass().getGenericInterfaces()[0]; Object o1 = JSON.parse(body); /** * 回调成功 */ callback.onSuccess(o1); } } }); } } } } } } return null; } }); /** * 扔到缓存中 */ serviceMap.put(clazz, o); } return (T) o; }

然后我们就能够依据Retrofit那样进行调用了

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

这仅仅是Retrofit中最简单的一个模块实现,假设对其它内容感兴趣,能够阅读retrofit的源代码。

Android开发中无处不在的设计模式——动态代理模式相关推荐

  1. android开发模式,Android开发中无处不在的设计模式

    Android开发中无处不在的设计模式――单例模式 Android开发中无处不在的设计模式――Builder模式 前面介绍了单例模式和Builder模式,有兴趣的见上面两个链接,这篇文章侧重介绍1下视 ...

  2. java中的静态、动态代理模式以及Spring中的CgLib动态代理解读(面试必问)

    java中的静态.动态代理模式以及Spring中的CgLib动态代理解读(面试必问) 静态代理 动态代理 CgLib动态代理     基础知: 反射知识 代理(Proxy)是一种设计模式,提供了对目标 ...

  3. Android开发中常见的设计模式

    对于开发人员来说,设计模式有时候就是一道坎,但是设计模式又非常有用,过了这道坎,它可以让你水平提高一个档次.而在android开发中,必要的了解一些设计模式又是非常有必要的.对于想系统的学习设计模式的 ...

  4. 研磨23种大话设计模式------动态代理模式 + 小结静态代理模式

    大家好,我是一位在java学习圈中不愿意透露姓名并苟且偷生的小学员,如果文章有错误之处,还望海涵,欢迎多多指正 如果你从本文 get 到有用的干货知识,请帮忙点个赞呗,据说点赞的都拿到了offer 在 ...

  5. 软件设计模式 | 动态代理模式

    文章目录 一.动态代理概述 1.1 代理的概述和作用 1.2 动态代理的优点 1.3 代理对象的创建 1.4 代理对象调用方法的执行流程 二.动态代理举例 2.1 歌手经纪人 2.2 业务功能的性能统 ...

  6. 在王者荣耀角度下分析面向对象程序设计B中23种设计模式之代理模式

    · 代理模式在王者荣耀中的应用 · 应用一(虚拟代理模式) 应用二(远程代理模式) 应用三(充值送好礼) 一.简述 应用一: 在王者荣耀这款游戏里,设置有很多种娱乐游戏模式,比如:无限乱斗.梦境大乱斗 ...

  7. Android开发中常见的设计模式深入浅出——观察者模式Observer

    ##最近老大写的Android项目里用到了RxBus然后我就去百度了 让我先了解RxJava 然后RxJava又是由观察者模式的变种写的 所以打算从头学一遍!!! 观察者模式 Observer 顾名思 ...

  8. 浅谈Android中的MVP与动态代理的结合

    浅谈Android中的MVP与动态代理的结合 本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 在Android开发平台上接触MVP足足算起来大概已经有一个年头左右.从最开始到现在经 ...

  9. 【Android NDK 开发】NDK 交叉编译 ( Ubuntu 中交叉编译动态库 | Android Studio 中配置使用第三方动态库 )

    文章目录 I . 动态库 与 静态库 II . 编译动态库 III. Android Studio 使用第三方动态库 IV . Android Studio 关键代码 V . 博客资源 I . 动态库 ...

最新文章

  1. Kotlin威胁、Python逆袭,2018年程序员需要升级哪些技能?(附报告下载)
  2. vs2010编译生成后清除obj目录
  3. 05_pandas读写文件,读写数据到CSV,HDF5,Excel中
  4. service 层 拼接的html 代码如何直接返回_代码分层的设计之道
  5. ue4 无限地图_UE4大地图(流关卡、无缝地图)
  6. Java Web学习笔记04:JSP隐含对象
  7. java修改cdm_Java™ ORM框架CDM教程 增删改查(四)
  8. 什么是:before和:after?
  9. WSS2.0 服务器启用SQL代理的解决过程
  10. cad卸载_盘点那些年用过的神级CAD插件,每一款都舍不得卸载
  11. GitHub 爬虫项目
  12. Android Mvp架构详解
  13. Android项目实践--《智慧校园》
  14. 关于防范ONION勒索软件病毒攻击的解决办法
  15. 高淇java300适合_高淇java300集JAVA面向对象的进阶作业
  16. 展讯SC8810平台虚拟机分析在QEMU中模拟运行
  17. 装黑苹果的那些事儿(以ThinkpadE540为例)
  18. 刨根究底字符编码之九——字符编码方案的演变与字节序
  19. 心理账户、沉没成本、比例偏见
  20. 二手交易网站 /二手交易平台/二手交易系统

热门文章

  1. leetcode402. 移掉K位数字
  2. ThinkPHP redirect 页面重定向使用详解与实例
  3. Linux(11)--(历史命令)Ctrl+r, history,!
  4. c++基础学习(11)--(模板、预处理器、信号处理)
  5. php ajax队列,AJAX请求队列实现
  6. getdevicecaps在哪个头文件里_一招定胜负,while (true) 和 for (;;) 到底哪个更快
  7. 专访雷果国:从1.5K到18K 一个程序员的5年成长之路
  8. 1分钟看懂:java 项目中 VO 、DTO、Entity,各自是在什么情况下应用的
  9. 解决:Unknown custom element: <myData> - did you register the component correctly? For recursive compon
  10. VSCode 汉化、设置为 中文语言显示 、中文界面