“代理”这个词这几年可谓是家喻户晓了,原因呢就是被微信好友或者朋友圈各种商品“代购”经常的刷屏!从此代理商或者代购这个新职业也进入了人们的眼中。
那么理解“代理模式”可以通过买东西代购来理解它,我们知道我们日常生活中需要的东西很多,有的一些甚至是一些国外大牌商品,有的时候我们需要购买他们的最新商品或者干脆就是国内商品短缺我们想要购买到商品怎么办呢?没错就是通过代购了,通过代购我们不需要亲自跑到国外的某个城市某个商店、也不需要关注如何拿到货之类的问题,我们只需要把钱给代购让他们直接帮我们拿到商品就行了,这样的模式其实就是“代理模式”了。
下面我们就来聊聊编程中GOF23种经典模式之一的代理模式,这里以java语言为例介绍。
代理模式是一种结构型设计模式,是开发中最常用的设计模式之一。
它是这样来定义的:为其他对象提供一种代理以控制对这个对象的访问。
代理模式主要用来解决:在直接访问对象时带来的一些问题,比如:我们需要为一个业务方法在执行前后记录日志,为了达到解耦的目的,我们就需要创建一个代理类来完成既可以调用原业务方法,又可以在调用前后进行日志处理。
代理模式的使用场景:在我们开发中非常的多,比如Spring容器的延迟加载,AOP增强处理、日志处理等。
代理模式的角色:
抽象角色:通过接口或抽象类声明真实角色需要被代理的业务方法。
委托角色(真实角色):被代理的对象,需要实现抽象角色中业务方法这样才会被代理业务方法;
代理角色:实现抽象角色,是真实角色的代理,通过实现抽象角色可以在真实角色实现业务的基础上添加增强功能和业务。
代理模式分类:
l静态代理
l动态代理
静态代理就是由程序员创建或工具生成代理类的代码,再对其进行编译。
之所以叫静态代理是因为在程序运行之前我们代理类的.class文件就已经存在了,代理类和委托类(真实角色)的关系和方法增强在程序运行前就已经确定了。
下面我们通过之前说的添加日志业务为例,来看下静态代理的实现:
分析:静态代理的特点就是在不影响真实角色业务方法的基础上进行了方法的增强,完成了业务和增强的解耦。缺点是代理类和委托类实现了相同的抽象接口,这样不仅会造成了代码的重复以后我们想要新增一个业务方法的时候,代理类和委托类代码改动的也比较大,并且一个代理类也只能代理一种类型的对象,如果想要代理其他类型的对象又需要按照我们上面写的一套重新写一套。
为了解决静态代理的缺点,于是java中就出现了动态代理模式。
动态代理是在程序运行期间,由JVM通过反射机制或者修改字节码技术实现生成代理类对象,在实现阶段我们不用关心代理类,而在运行阶段才指定哪一个对象,因为这里的代理类不是由程序员编写的而是由系统动态生成的所以叫动态代理。
Java中动态代理的实现方式主要有两种:
lJDK动态代理
JDK动态代理是利用反射机制在程序运行过程中生成代理对象,JDK的动态代理只能代理实现了接口的类。
lCGLib动态代理
CGLib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。可以代理没有实现接口的类。
这两种动态代理的实现方式其实也是java经典框架spring里面使用的两种方式。
因为JDK动态代理是由JDK提供的所以我们可以直接使用,而CGLib是第三方开源的需要下载和导入第三方的jar包或者依赖,所以这里我们主要讲解JDK动态代理的实现。
JDK动态代理实现:
JDK动态代理实现步骤:
(1) 创建一个实现接口InvocationHandler的类;
(2) 在自定义InvocationHandler实现类中调用Proxy的newProxyInstance静态方法,创建一个代理类。
(3) 重新实现类的invoke方法,添加增强功能。
(4) 通过代理对象调用目标方法。
代码实现:
我们的抽象接口UserService和为拖累UserServiceImp还是不变,下面我们只需要完成InvocationHandler实现类即可。
分析:动态代理与静态代理相比较,最大的好处就是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强。
以上就是代理模式的实现了。