Proxy mode explained

我们现在来学习代理模式,我们首先看一下代理模式的定义与类型,他的定义是说,为其他对象提供一种代理,以控制对这个对象的

访问,代理对象在客户端和目标对象之间呢,起到一个中介的作用,那这句话如何理解,就和我们租房子是一样的,假设我们找中介,

租房子,然后呢租那种全托管的房子,最后出租出来的房子呢,是房东,房东呢,就是目标对象,那水电费结算,都是代理类来做的,

代理类就是中介,但是我们直接可以和代理,也就是和租房中介来签租房合同,不需要和房东直接接触,也就是中介代理房东,

来和我们签这个合同,并且他对目标对象进行了一个增强,例如在签合同之前,先草拟合同,签完合同之后呢,还进行了一些水电费

核算的,这些工作,那这两点可以理解成,租房子的一些方法,对他的一个增强,那你们学Spring都用过AOP,那AOP就是面向切面编程,

OOP就是面向对象编程,那AOP里面的before和after,就可以理解成before就是草拟合同,after就是水电费结算,而要增强的目标方法呢,

正是租房子这种行为,那他的类型是结构型

然后我们来看一下代理的适用场景,首先保护目标对象,例如租房子,我们可能连房东面都没见过,

房东长什么样我们都不知道,然后呢增强目标对象,那增强目标对象呢,这里面范围也比较大,比如增强

目标对象的一个租房子,这个行为方法,也是增强目标对象


那我们可以看一下代理对象的优点有哪些呢,首先代理模式能将代理对象与真实被调用的目标对象进行分离,

这个呢还是很好理解的,然后第二点,在一定程度上降低了系统的耦合度,扩展性比较好,第三点保护目标对象,

那因为代理模式,在客户端和目标对象之间,起到一个中介作用,代理模式可以拿到真实对象的引用,而客户端呢,

和代理类进行交互,然后就是增强目标对象

例如before和after,我们看一下代理模式有哪些缺点呢,第一条很容易理解,代理模式会造成系统设计中类的增加,

如果我们使用代理模式,肯定要添加一些代理类,这个就导致类的数目增加,然后在客户单和目标对象之间,增加了一个

代理对象,会造成请求速度变慢,当然这个是根据具体的业务场景来看,包括进行压测,还有大批量的测试,多线程的并发,

等等,这个和系统的应变也是有关的,那这个呢也很好理解,例如增强了目标对象的方法,执行的代码多了,从理论上来说,

相对速度肯定会变慢,然后呢就是增加了系统的复杂度,那我们实现了代理模式,需要额外的工作,那有些代理模式的实现,

非常复杂,自然增加了系统的复杂度

接下来我们看一下代理模式的扩展,首先呢是静态代理,以后我也会带着一起来coding静态代理,静态代理非常简单,

就是在代码中显示指定的代理,那我们来看一下还有动态代理,那JDK中的动态代理呢,只能对实现接口的类生成代理,

他并不能针对一个具体的实现类,JDK当中主要分为静态代理和动态代理,这里面一定要注意,动态代理无法代理类,

但是可以代理接口,那在JDK动态代理当中呢,用到的代理类是在程序调用到代理类对象时,才有JVM真正创建,JVM根据

传入的业务实现类对象,以及方法名,动态的创建了一个代理类的class文件,并且这个class文件对字节码引擎执行,然后通过该代理类的

对象,进行方法调用,那我们要做的就是把代理类里面的实现,写好,例如说before怎么写,after怎么写,这个都是目标对象的一个方法层次

的一个增强,那如果我们的业务实现类没有实现接口,而是直接定义业务方法的话,就无法使用JDK的动态代理了,那还有一种情况,

假设我们写一个接口,里边有两个方法,一个是A方法,一个是B方法,然后也写了这个接口的实现,A和B,那如果我们在接口实现中,

增加新方法,但是接口中并没有声明B方法,这个方法也是无法被代理的,这个还是很好理解的,然后我们再看一下扩展,CGLib代理,

CGLib是可以代理类的,他就是根据类实现进行代理,他的实现原理是什么呢,很简单,如果我们代理一个类,CGLib会生成一个被代理类的

子类,覆盖其中的方法,也就是说通过继承,然后还有重写,那因为它使用的是继承,所以我们要考虑一下,如果这个是类是final的,那这个类

是无法被继承的,那如果这个类不是final的,里边的方法是final的,那么这个方法也是无法被重写的,所以使用CGLib代理的时候,

对于final这个修饰符,一定要额外关注,那平时我们工作的时候,对于使用CGLib code review的时候,我们也会格外检查,关于

final这个修饰符的使用情况,只所以这里说了这么多,就是为了强调,使用CGLib的时候,一定要注意,final这个修饰符,那对于这三类呢,

简单总结一下,首先静态代理,是通过在代码中,显示的定义一个实现类的代理,在代理类中,同名的业务方法,进行包装,用户通过

代理类的包装过的业务方法呢,来调用目标方法的业务方法,通过对目标对象的业务方法,进行增强,那JDK的动态代理呢,是通过接口中

的方法名,在动态生成的代理类中,调用业务实现类的同名方法,这里边要注意,一定是接口,那CGLib动态代理呢,是通过继承,来实现的,

生成的动态代理类呢,就是业务类的子类,然后通过重写业务方法,进行代理,都是非常好理解的,然后我们继续扩展,那因为代理模式在

我们平时工作中使用的比较多,那我说的这种使用,并不是说,然后我们一起来写,静态代理和动态代理,写一个CGLib代理,而是说我们

在使用Spring的时候,里面很多代理的一些原理,要理解,所以这里里面多加了一些

用Spring的时候,里面很多代理的一个原理,我们要理解,所以这里加了一些扩展模式的扩展,那我们来看一下,

Spring的代理选择,这里也是扩展内容,首先当Spring的Bean有实现接口时,那Spring就会用JDK的动态代理,

当这个Bean没有实现接口时,Spring就会选择使用CGLib,那当然我们也可以强制的使用CGLib,也就是说在Spring

的配置当中,加入这么一个配置,就OK了,proxy-target-class,等于true,这里再给大家提供一下spring-code参考

资料,这个是官方文档,非常不错,平时也会抽时间来看一看,特意放到这里呢,就是希望你们,有时间的时候,

可以来看一下,对应的官方文档,那既然说有JDK的动态代理,还有CGLib的类代理,那他们的速度对比是怎样的呢

代理速度的对比,也是扩展的内容,首先对于CGLib我们要了解,他的原理,那CGLib底层,是采用ASM字节码生成的,那我们之前,

通过这种方式,比使用JAVA反射,效率要高,但是我们一旦使用CGLib的时候,一定要对final这个修饰符,额外关注,然后是JDK的

动态代理,这个就是JDK的原生的代理实现,那他们速度对比是什么样呢,有兴趣的话你们自己可以试一下,在万次执行的情况下呢,

JDK7和JDK8的动态代理性能要比CGLIB要大约块20%左右,那这些在我们实际工作中,假设这个类,只能用CGLib来代理的话,其实这个

速度也可以忽略,当然对于业务特别苛刻的业务场景,那这个代理方式,也要注意,这个还是要根据实际的业务需要来选择哪种方式,

因为这里是有开发成本的,我们来看一下代理模式的相关设计模式

首先代理模式和装饰者模式,那代理模式和装饰者模式呢,实现上非常相似,但是目的不同,装饰者模式是为对象

加上行为,而代理模式呢,是控制访问,代理模式更加注重通过设置代理人的方式,来增强目标对象,那他增强目标对象的

方式呢,一般是通过增强目标对象的某些行为,然后是代理模式和适配器模式,适配器模式主要是改变考虑对象的接口,

而代理模式呢,是不能改变锁代理类的接口的

 

Guess you like

Origin blog.csdn.net/Leon_Jinhai_Sun/article/details/91041988