Java中的代理模式
意图: 为其他对象提供一种代理以控制对这个对象的访问。
何时使用: 想在访问一个类时做一些控制。
关键代码: 实现与被代理类组合。
应用实例: spring aop,retrofit,binder,。
优点:
1、职责清晰。
2、高扩展性。
3、智能化。
缺点:
1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
注意事项:
1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。
2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。
1、静态代理
作用:
通过引入代理对象的方式来间接访问目标对象,防止直接访问目标对象给系统带来的不必要复杂性。
2、动态代理
首先为了解决静态代理模式中存在的问题:
- 1个静态代理 只服务1种类型的目标对象
- 若要服务多类型的目标对象,则需要为每种目标对象都实现一个静态代理对象,会出现 静态代理对象量多、代码量大,从而导致代码复杂的问题
实现原理:
设计动态代理类(
DynamicProxy
)时,不需要显式实现与目标对象类(RealSubject
)相同的接口,而是将这种实现推迟到程序运行时由JVM
来实现
- 即:在使用时再创建动态代理类 & 实例
- 静态代理则是在代理类实现时就指定与目标对象类(
RealSubject
)相同的接口通过
Java
反射机制的method.invoke()
,通过调用动态代理类对象方法,从而自动调用目标对象的方法。
优点:
- 只需要1个动态代理类就可以解决创建多个静态代理的问题,避免重复、多余代码
- 更强的灵活性
缺点:
- 效率低
- 相比静态代理中 直接调用目标对象方法,动态代理则需要先通过
Java
反射机制 从而 间接调用目标对象方法- 应用场景局限, 因为 Java 的单继承特性(每个代理类都继承了 Proxy 类),即只能针对接口 创建 代理类,不能针对类 创建代理类
静态代理与动态代理的区别主要在:
- 静态代理在编译时就已经实现,编译完成后代理类是一个实际的class文件
- 动态代理是在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中
特点:
动态代理对象不需要实现接口,但是要求目标对象必须实现接口,否则不能使用动态代理。
使用方式:
1.需要实现 InvocationHandler 接口
2.复写InvocationHandler接口的invoke()
3.动态代理对象调用目标对象的任何方法前,都会调用处理器类的invoke()
应用场景:
Spring中的 AOP,面向切面编程。
测试:
这样我们就可以给实现了 IShop 接口的不同对象做代理。
安卓中的动态代理:
1.Retrofit
2、AIDL 动态代理
Binder是一个非常典型的代理模式,是一种远程代理,实际上Proxy代理的是另外一个进程中的Stub对象。内部是将接口函数标记为对应的ID,然后根据这个ID来标识目前调用的是哪一个函数。由DESCRIPTOR来作为Token分隔不同的接口调用,另外通过Parcel来写入函数参数和接受函数返回值(Stub端对应接受参数和写入结果)。
cglib代理
cglib特点
- JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。
如果想代理没有实现接口的类,就可以使用CGLIB实现。- CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。
- CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。
不鼓励直接使用ASM,因为它需要你对JVM内部结构包括class文件的格式和指令集都很熟悉。
cglib与动态代理最大的区别就是- 使用动态代理的对象必须实现一个或多个接口
- 使用cglib代理的对象则无需实现接口,达到代理类无侵入。