Android开发中无处不在的设计模式——动态代理模式
来源:互联网 发布:淘宝可以领券的网站 编辑:程序博客网 时间:2024/04/29 23:51
继续更新设计模式系列,写这个模式的主要原因是最近看到了动态代理的代码。
先来回顾一下前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中大量的用到,但是在客户端,由于考虑到性能的问题,所以用动态代理都会慎重考虑,但是,一旦动态代理用的好,就会产生不一样的效果,就比如这个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() { @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注解的值 */ 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>>() { @Override public void onSuccess(Object t) { System.out.println(t); } @Override public void onFailed(Exception e) { }});
这只是Retrofit中最简单的一个模块实现,如果对其他内容感兴趣,可以阅读retrofit的源码。
- Android开发中无处不在的设计模式——动态代理模式
- Android开发中无处不在的设计模式——单例模式
- Android开发中无处不在的设计模式——Builder模式
- Android开发中无处不在的设计模式——观察者模式
- Android开发中无处不在的设计模式——原型模式
- Android开发中无处不在的设计模式——原型模式
- Android开发中无处不在的设计模式——策略模式
- Android开发中无处不在的设计模式——Builder模式
- Android开发中无处不在的设计模式——装饰者模式
- Android开发中无处不在的设计模式——工厂模式
- Android开发中无处不在的设计模式——单例模式
- Android开发中无处不在的设计模式——Builder模式
- Android开发中无处不在的设计模式——单例模式
- Android开发中无处不在的设计模式——观察者模式
- Android开发中无处不在的设计模式——Builder模式
- Android开发中无处不在的设计模式——策略模式
- Android开发中常用的设计模式 --- 动态代理模式
- Android中设计模式无处不在之简单工厂模式和代理模式
- xutils 注册 控件转换异常信息处理
- Android ImageCache图片缓存,使用简单,支持预取,支持多种缓存算法,支持不同网络类型,扩展性强
- Spring概述
- IDFA - 3
- 在安装discuz!nt时,数据库用户登录失败的问题时,sql server 2008 数据库更改登录模式(sql server 2008 混合登陆中SqlServer身份验证用户名密码)
- Android开发中无处不在的设计模式——动态代理模式
- js数组实现队列和栈
- 调用UIImagePickerController之处理statusBar
- Linux同时抓取多台服务器日志进行分析
- Oracle 12c win7-64安装步骤
- 端口占用查询
- Web前端开发规范文档(css/javascript)
- label 省略号颜色改变
- MSSQL 常用的聚合函数