什么是代理模式
代理模式也称为委托模式,属于结构型模式之一。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用
代理模式分类
静态代理是由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行之前,代理类.class文件就已经被创建了
动态代理是在程序运行时通过java反射机制动态创建的。
代理模式的目的
代理模式主要有两个目的:一保护目标对象,二增强目标对象。
静态代理
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类.
关键:在编译期确定代理对象,在程序运行前代理类的.class文件就已经存在了。
模拟保存动作,定义一个保存动作的接口:IUserDao.java,然后目标对象UserDao.java实现这个接口的方法,此时如果使用静态代理方式,就需要在代理对象(UserDaoProxy.java)中也实现IUserDao接口.调用的时候通过调用代理对象的方法来调用目标对象.
实例
1 | public interface IUserDao { |
1 | public class UserDao implements IUserDao { |
1 | public class UserDaoProxy implements IUserDao{ |
1 | public class App { |
静态代理总结:
可以做到在不修改目标对象的功能前提下,对目标功能扩展.
缺点:
代理类和委托类实现相同的接口,同时要实现相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
动态代理
- 在运行期,通过反射机制创建一个实现了一组给定接口的新类
- 在运行时生成的class,必须提供一组interface给它,然后该class就宣称它实现了这些 interface。该class的实 例可以当作这些interface中的任何一个来用。但是这个Dynamic Proxy其实就是一个Proxy, 它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工 作。
- 动态代理也叫做:JDK代理,接口代理
- 接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强
实例代码
1 |
|
1 | /** |
总结
代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理
Cglib代理
上面的静态代理和动态代理模式都是要求目标对象实现一个接口或者多个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用构建目标对象子类的方式实现代理,这种方法就叫做:Cglib代理
Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.
*Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)
- Cglib包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的子类.
* 代理的类不能为final,否则报错;目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.
如果不是spring(spring已经集成了 CGLIB )环境需要先引入 jar 包:
1 | <dependency> |
实例代码
1 | /** |
1 | /** |
1 | /** |
代理模式与装饰者模式的区别
UML类图基本没区别,都是实现同一个接口,一个类包装另一 个类。 两者的定义:
- 装饰器模式:能动态的新增或组合对象的行为
在不改变接口的前提下,动态扩展对象的功能 - 代理模式:为其他对象提供一种代理以控制对这个对象的访问
在不改变接口的前提下,控制对象的访问
装饰模式是“新增行为”,而代理模式是“控制访问”。关键就是我们如何判断是“新增行 为”还是“控制访问”。你在一个地方写装饰,大家就知道这是在增加功能,你写代理,大 家就知道是在限制。