一文彻底搞懂静态代理和动态代理

先看下机制上的区别:

静态:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。
动态:在程序运行时运用反射机制动态创建而成。

那么由我来一步步解析为什么产生这样的写法

最基本的,举个例子:使用第三方库加载一个图片

然后发现不够优美,我们是面向对象编程的开发者!于是我们给方法放进了对象

嗯,好像可以了,这下只需要new一个ImageLoaderImpl,然后调用disPlayImage就可以了,美滋滋下班!
等用了一段时间,PM找你谈话了,说Glide不太符合我们的需求,需要换成Picasso(这俩的区别这里就不说了,本文重点不是这里)
于是你就将disPlayImage的方法改成Picasso的实现了,如果这时候你留了个心机只是把Glide的实现给注释掉然后加上Picasso的实现还好,否则等后面PM又过来说还是换回Glide吧,你就要抓狂了!加上各种加载框架的属性,1个小时又没了!

于是你聪明地想了想,能不能搞个类似代理的东西,你只管调用,具体实现放到另一个地方进行解耦呢?

然后调用的地方变成了这样:

嗯,利用多态,看起来有那么点意思了!
然后为了达到代理的目的,我们给后面套了个壳,然后变成这样了:

到时候我们可以写两个类,一个类实现Glide的逻辑,一个类实现Picasso的逻辑,到时候只需要在调用地方把ImageLoaderImpl给替换就可以了。

引申:于是小伙伴要发问了!你直接把ImageLoaderImpl给替换不也是一样的吗?干嘛还要写个代理类?

答:那么我们就需要讨论其他情况了,如果这里不是在加载图片,而是从类似线程池中拿到缓存的对象,也就是ImageLoaderImpl你不能随便new,可能OOM!

ok,这就是静态代理的演化过程了,然后有的小伙伴可能又要说了,你这里代理类和具体的实现类都是实现类你自定义的接口,那以后接口每增加一个方法,那就要在两边都要增加具体实现啊!代码量蹭蹭往上涨!

为了解决这个问题,动态代理出现了,动态代理可以为我们自动生成proxy类,也就是说proxy类不需要我们自己去实现类,JVM会自动帮我们生成proxy类。

具体的反射过程不用我们自己写了,在reflect包中就有Proxy这个类,让我们来看看修改之后的类是什么样子的


如图所示,我们只需要实现InvocationHandler,然后传入自己的实现类即可,Proxy.newProxyInstance就是系统会帮我们自动生成的代理类(这个过程我们后面再看流程),然后调用接口类的时候就会调用ImageHandler的invoke方法,最终调用到我们的具体实现类的对应方法!那么省去写一个代理类还是相当香的!

有小伙伴又要问了,我们使用retrofit的时候根本连实现类都没有写!这个是怎么实现的呢?那么我们来看看retrofit具体的代码。

前面的都一样,我们直接来看使用到动态代理的这块代码:


看来这个loadServiceMethod就是对应的实现类的实现了

ServiceMethod是一个抽象类,我们可以看到,唯一实现类是HttpServiceMethod

从这里应该都清楚了,结合我之前的一篇博客:https://blog.csdn.net/Genius_sasuke/article/details/105860291
可以知道这里就是根据我们自定义的接口里的方法的返回值,注解,参数,生成对应的HttpMethod对象,然后我们客户端调用接口方法,会间接调用InvocationHandler的invoke方法,最终转到CallAdapter实现类的adapt方法,也就是它唯一实现类BodyCallAdapter的adapt方法!

啊~~熟悉的call.enqueue!

那么现在来补一下前面的坑:到底是怎么生成代理类的,先做一个猜测,既然retrofit是通过解析方法返回值和参数等进行生成实现类,那么代理类是不是也是通过类似的方法呢?


先看getProxyClass0

又是缓存!proxyClassCache是一个WeakCache类,我们获取的是ProxyClassFactory,看他的生产方法


这里巧妙的用自增数值来区分代理类,接下来就是具体的生成代理类逻辑了:
点进去发现是native方法,那么就不再深究了,生成代理类的结构如下:

调用invoke方法的时候就是通过代理类再调用InvocationHandler的invoke方法,如此便完成了动态代理!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值