前言
最近在研究Retrofit的原理,其中核心的部分是通过动态代理来实现的,虽然之前了解过,但对于这个设计模式,一直处于懵懂状态,从来没用过,就着这个机会,又深入研究了一下。代理模式类似于现实生活中的委托,实现方式上可以分为静态代理和动态代理。上图是代理模式UML图。
为什么要使用代理模式?
对于熟悉这个模式的人来说,代理模式实现起来非常简单,那你可能会问,为什么要使用代理模式,或者说使用代理有什么好处呢?下面我们一一来分析
-
实际执行过程中,额外做一些别的事情
举个例子:果农在自家生产水果,由于人力物力等原因,不能零售,所以果农把水果卖给水果商贩,由商贩在全国各地售卖。这里果农是被代理者,水果商贩是代理者;商贩在售卖前,为了吸引人购买,需要对水果做一些处理,如对水果进行清洗,打蜡,削皮等等;在卖出水果之后,商贩还可以根据售卖情况进行汇总,选出热销水果,方便后面多进些货等操作
-
用户和被代理对象隔离,被代理对象只需关注自身业务,可以实现复用
还拿上面的例子来说,用户只和水果商贩打交道,不和果农产生直接联系,体现了隔离;果农只负责种水果和卖给水果商贩,业务比较专;而且一个果农可以很多个水果商贩打交道,体现了果农的复用特性
以上分析和举例只是为了说明代理的优势,不得当之处还请见谅。
静态代理 vs 动态代理
前面提到了代理分为静态代理和动态代理,这两种代理只是在java语言特性上创建代理类的不同实现方式,实际产生的效果是相同的,所以上面分析的优势仍然适用二者。下面,来看看二者的区别吧
类别 | 作用阶段 | 需实现抽象方法个数 | 代理执行方式 |
---|---|---|---|
静态代理 | 编码阶段 | all | 单独代理,一一对应 |
动态代理 | 运行阶段 | 0 | 统一管理 |
- 静态代理:在编码阶段创建代理类,直接使用该代理类型的对象;由于代理类需要继承被代理类的抽象,所以需要实现所有的抽象方法,抽象方法很多的情况下,管理起来就变的非常繁琐。
- 动态代理:在运行期间,自动在内存中创建一个代理对象,不需要创建具体的代理类型;通过实现InvocationHandler接口,直接实现委托对象方法的调用,InvocationHandler的invoke()方法,代理了委托对象的所有方法,即委托对象的每一个方法调用,都会调用invoke()方法,也因此导致invoke()方法实现起来比较复杂。
静态代理
以上都是代理模式的理论,下面是时候来展示一下它们的神奇了。以上面举的例子为基础,看看编码是如何实现的。实现静态代理,主要有以下4步(从UML就可以看出来了哦)
- 创建委托类的抽象
/** * @Description: 抽象类-卖水果 */interface IFrultSell { fun sellFrult(frultName: String): Unit}复制代码
- 创建具体委托类,可能有多个
/** * @Description: 被代理类-果农 */class FrultGrower : IFrultSell { override fun sellFrult(frultName: String) { println("我是果农,出售自己种植的$frultName") }}复制代码
- 创建代理类
/** * @date: 2019/5/10 * @author: zzf * @Description: 代理类-水果商贩 */class ProxyProduct(var applePro: IFrultSell?) : IFrultSell { override fun sellFrult(frultName: String) { println("出售精品$frultName,干净无农药") applePro!!.sellFrult(frultName) println("统计卖出的数量") }}复制代码
- 做完了所有的准备工作,接下来就是使用了
/** * @Description: 消费者 */object Consumer { @JvmStatic fun main(args: Array): Unit { //创建果农对象 val fruPro: IFrultSell = FrultGrower() //创建代理对象 val frultSeller = ProxyProduct(fruPro) val banana = Frults.BANANA //用户调用 frultSeller.sellFrult(frultName = banana.getName()) }}复制代码
以上就是静态代理完整的实现过程,注释很详细,就不做过多的解释了,下图是执行的过程
动态代理
介绍完了静态代理,剩下的就是动态代理的实现了,且听我娓娓道来,哈哈。 还是以上面的例子为基础,动态代理的实现共4步,分别是
- 创建委托类的抽象
/** * @Description: 抽象接口-卖水果 */interface IFrultSell { /** * 卖水果 */ fun sailFrult(name: String): Unit}复制代码
- 创建具体委托类,可能有多个
/** * @Description:被代理类-果农 */class FrultGrower() : IFrultSell { override fun sailFrult(name: String) { println("我是果农,出售自己种植的$name") }}复制代码
- 创建动态代理执行器,此处开始区别于静态代理
/** * @Description: 动态代理的InvocationHandler */class FrultHandler(var iFrult: IFrultSell) : InvocationHandler { override fun invoke(proxy: Any?, method: Method?, args: Array?): Any? { if (method!!.name.equals("sailFrult",false)){ //代理的是卖水果的操作,可以在此进行额外操作 println("大家快来看啊,我这里有${args!![0]}出售") } val result = method.run { invoke(iFrult, *args!!) } //代理执行完毕,可以在此执行额外操作 println("代理执行操作完毕~ ~") return result }}//invoke()作为代理的公共方法,代理所有委托方法的实现复制代码
- 运行时创建代理并使用
/** * @Description: */object Consumer { @JvmStatic fun main(args: Array): Unit { //声明被代理者(果农) val seller: IFrultSell = FrultGrower() //声明代理的处理者 val handler = FrultHandler(seller) //创建代理对象 val iFrult = Proxy.newProxyInstance(IFrultSell::class.java.classLoader, arrayOf(IFrultSell::class.java), handler) as IFrultSell //用户调用 iFrult.sailFrult("苹果") }}复制代码
如上所示,通过Proxy.newProxyInstance()方法创建一个代理对象,InvocationHandler对象作为参数,当调用代理对象的方法(如iFrult.sailFrult())时,会回调InvocationHandler.invoke()方法,执行我们预设的逻辑。所以,动态代理的实现流程还是很简单的,而要说复杂的地方,是在代理执行器InvocationHandler.invoke()的处理上,因为此处需要通过反射实现,具体的实现就要根据自己的业务而定了。老样子,下图是动态代理的执行结果,和静态代理的结果相同