首先这个代理并不是网络层的那个代理,是一种设计模式,前天在看一篇Retrofit解析的文章时讲到一点:Retrofit使用动态代理(
Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler()
)实现接口类和okhttp封装的一个调用环节,这是第一次看到这个东西(请恕我孤陋寡闻- -!),于是也就好奇这个是干什么的,查了一下网上对静态动态的解释还真的是有好多细节的不同,看着看着都晕了。最主要的是没有一定的应用场景这个就尴尬了。所以这篇就来理一理我所理解的静态代理与动态代理及它可能被应用的场景。
�
以下匀个人愚见,如有不对还请指出。
角色
- 抽象角色:接口类
- 实现角色: 实现类
- 代理角色:代理实现的类,最终使用的对象
静态
接口类与实现类就不说了这个所有开发人员都知道网上写的也都一样:
而代理类写的很多就有点差异了。总体理解下来大概可以这么说:就是对实现类再次包装的类。
我们实现不同接口类,实例化对应的实现类,并调用对应的方法。
优点:使用者只关心业务逻辑,不需要着眼内部实现,方便后期的变更和部分共用代码的统一处理
缺点:当代理类中出现的被代理类越来越多时,内部就会显得非常臃肿。反而不利于管理阅读。
应用:一些第三方框架的代理,便后后期替换或者定制化变更。
动态代理
这个是由java封装好的一个静态方法直接完成的,也就是最开始提到Retrofit使用的动态代理方法Proxy.newnewProxyInstance
它需要三个参数Proxy.newProxyInstance(接口类的ClassLoader, 接口类的class, 实现了InvocationHandler的类)
前两个参数通过接口可以直接获取,而第三个参数就是我们真正需要实现的部分了。
当你实现InvocationHandler类时需要重写invoke(Object proxy, Method method, Object[] args)
方法。返回的分别是:接口类、方法、参数。然后内部通过反射调用被代理的类的方法。
�我们可以再进一步封装一下这样写。
这样就有了一个简易“模板”的东西。省去了很多代码完成了相同的任务。�
使用起来是这样:
在
bindSubject
方法中传入实现类就可以对其进行代理。然后你会发现在调用subject.request()
时就会去调用MyInvocationHandler
中的invoke方法了。而这时invoke
返回的参数就是(subject类,request方法,对应的参数(当然这是个无参的就是空的了))
关于java动态代理的内部实现大家可以看这篇文章:
http://blog.csdn.net/zhangerqing/article/details/42504281/
优点:拥有静态代理的优点,同时省去了很多代码,并且扩展性更强,通过反射可以执行任意类型的被代理类方法
缺点:只能代理实现了接口的类,而没有实现接口的类就不能实现动态代理。�通过反射在性能上可以会有一定程度上的性能损耗。
应用:被代理类庞大时,需要在某些方法执行前后处理一些事情时,亦或接口类与实现类经常变动时(因为使用反射所以方法的增删改并不需要修改invoke
方法)。