Dubbo中应用的设计模式

这里就是一个简单的整理和概括。
而且设计模式这种又不是1+1等于2这种确定答案的题目。而有的时候某种设计会类似A又类似B,甚至还借用了C的一些理念。所以如果有的说的不准确欢迎指出。我这里也都是按照书中的内容整理的。

工厂模式

简单说下工厂模式:工厂模式一种创建对象的模式,它被广泛应用在jdk中以及Spring和Struts框架中。是将创建对象的责任转移到工厂类。
简单通俗的用自己的话讲一下:因为我最开始学设计模式是看的大话设计模式,这里也用大话设计模式中的demo来举例:比如说两个数的计算。无论是加减乘除,都是以两个数为参数的计算,所以我们可以把+- * /看成四个子类。然后用一个统一的超类(超类可以是接口、抽象类、父类)对外。再写一个工厂类根据输入的计算符号的不同选择相应的子类new,这样就是工厂方法模式。

好处就是不管输入+- * /那种计算符号,对外的都只有一行代码,使用的时候很简单。而且扩展性也比较好。假如这个计算器已经是写好了的代码。但是现在我们要实现取余计算。我们实现起来就可以自己写一个取余的类,继承之前的超类,实现方式是取余。然后我们在工厂类中添加取余符号走取余子类就好了。
这样哪怕我们取余有问题,但是+-*/都是不影响的。所以说扩展性比较好。
在JDK中大量的使用了这种模式。比如我们常用的日历类就是。这里有个小窍门:一般getInstance() 的都是工厂模式哦~
而dubbo中,Provider在 export服务时,会调用 ServiceConfig的 export方法。ServiceConfig 中有个字段:

private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtensi on();

这个protocol的创建就是交给工厂创建的。像上面的 Adaptive 实现,可以做到调用时动态决定调用哪个实现,但是由于这种实现采用了动态代理,会造成代码 调试比较麻烦,需要分析出实际调用的实现类。
其实我这么说可能不是很准确,但是如果我们在阅读代码的时候发现有对象的创建不是直接new,点进去发现是条件判断实例化不同类的代码。这种多半都是这种工厂模式。

装饰器模式

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
上面是这个模式的介绍,再用自己的话简单说下:其实就是在现有功能的基础上,添加一些额外的功能。比如上面说的计算器,假如要额外加个功能:对于结果可以取整,也可以取两位小数,还可以取三位小数。
这样的一个功能我们如果想在计算的时候就计算,首先每个计算类都只能算出自然结果,再去取整/取两位/三位小数就破坏其原有的结构和代码了,肯定不现实。
这里要说下:在设计模式中没有加一层解决不了问题!如果有的话,那就加两层。
所以想解决这个问题就可以用到装饰器模式:
在工厂类的外面加一层装饰类:这个类也继承工厂类。并且重写其公共方法:这个方法就是调用子类的这个方法。重点是调用完子类的方法还可以自己对这个结果做点什么:比如取整/取两位小数等。然后再返回。
这样我们对外的类就是这个装饰类了:通过这个装饰类来先对结果取整了。

其实我这个demo不是很合适,因为计算器本身是可以只获取加减法计算的类的。但是我们如果用到装饰类,那么只能获取结果了。但是大概意思明白就行了。
总而言之装饰类模式其实更像是在我们已经决定好的对外的类的上面再加上一层。
Dubbo 在启动和调用阶段都大量使用了装饰器模式。以 Provider 提供的调用链为 例,具体的调用链代码是在 ProtocolFilterWrapper 的 buildInvokerChain 完成 的,具体是将注解中含有 group=provider 的 Filter 实现,按照 order 排序,最 后的调用顺序是:

EchoFilter -> ClassLoaderFilter -> GenericFilter -> ContextFilter -> ExecuteLimitFilter -> TraceFilter -> TimeoutFilter -> MonitorFilter -> ExceptionFilter

更确切地说,这里是装饰器和责任链模式的混合使用。例如,EchoFilter 的作用是 判断是否是回声测试请求,是的话直接返回内容,这是一种责任链的体现。像 ClassLoaderFilter 则只是在主功能上添加了功能,更改当前线程的 ClassLoader, 这是典型的装饰器模式。

责任链模式

因为上面说的dubbo的调用链就是装饰器和责任链混合模式,所以也简单说下什么是责任链模式:
将能够处理同一类请求的对象连成一条链所提交的请求沿着链传递,链上的对象逐个判断是否有能力处理该请求, 如果能则处理,如果不能则传递给链上的下一个对象。
这个我记得大话设计模式中是用请假来讲的?记不太清了,这都是三年前看的书了。反正现在也可以用这个例子来理解:
比如说一个小职员想请假,问小组长我可以请假么? 小组长说我没这个权限,你去问大组长吧。 然后大组长说我也没这个权限,去问经理吧。 经理说我有这个权限,我给你批了吧。
从小组长->大组长->经理。 这个就是一个责任链。当然了经理不见得是最后一个,因为请假要求的资格低。如果是想要加薪,那么就还要往上走,经历不能决定那么去问总经理,总经理不能决定就去问董事长。直到能处理的就结束了。
当然这样就有个问题,也是责任链的缺点:不能保证请求一定会执行,可能或落到责任链之外。
Java中的异常机制就是一种责任链模式,catch链就是一种责任链。因为这个几乎每个人都用过,所以就不多说了,继续往下。

观察者模式

当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。
其实这个比较号理解,叫做观察者也行,其实叫监视更好理解:大话设计模式中好像是用上班,其中一个员工看着领导。领导来了告诉别的同事,别的同事就假装工作来举例子的。其实比较好理解,我们常用的socket应该也有这种模式的影子。其优点和缺点相当的多,这里我直接放菜鸟教程中的介绍:

观察者模式

其实我觉得这个是比较容易理解的,其实不仅仅是dubbo,我们之前说的zookeeper中的监听应该也是观察者模式。所以这个就不多说了。
Dubbo 的 Provider 启动时,需要与注册中心交互,先注册自己的服务,再订阅自己的服务,订阅时,采用了观察者模式,开启一个 listener。注册中心会每 5 秒定时检查是否有服务更新,如果有更新,向该服务的提供者发送一个 notify 消息,provider 接受到 notify 消息后,即运行 NotifyListener 的 notify 方法,执行监听器方法。

动态代理模式

代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法
这个模式要好好说一说。因为很多时候维护现有项目或者二开项目都是一个常见的情景。毕竟所以尽量在原有的基础上增加而不是修改就变得很重要了。也经常听说那种例子:删除了一个打印语句整个项目都瘫痪了(虽然这个听起来太扯了)。但是也不得不说告诉我们确实尽量少修改现有的代码。
这个时候,代理模式就很重要了。
其实动态代理模式我们可以理解成代理模式中的一个分类:代理模式分为->动态代理模式/静态代理模式/Cglib代理模式(基于继承实现的)。
这里我们要说的是动态代理模式。当然了,也会简单说下其余两个。
静态代理模式:其实刚刚我说定义的时候大家可能就会觉得眼熟,这个功能和装饰器模式有点类似。也确实是,静态代理确实类似于装饰器模式。
动态代理模式:动态代理模式就和装饰器模式大不相同啦。动态代理模式不需要自己写接口或类。代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)所以动态代理也叫做:JDK代理,接口代理
就好像我们第一个说工厂模式的时候,Dubbo 扩展 JDK SPI 的类ExtensionLoader 的 Adaptive 实现就是典型的动态代理实现。Dubbo 需要灵活地控制实现类,即在调用阶段动态地根据参数决定调用哪个实现类,所以采用先生成代理类的方法,能够做到灵活的调用。生成代理类的代码是 ExtensionLoader 的 createAdaptiveExtensionClassCode 方法。代理类的主要逻辑是,获取 URL 参数中指定参数的值作为获取实现类的 key。这里其实大概的通俗理解:动态代理就是我们根据传递的参数的不同获取不同的目标类。over~
代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理。
Cglib代理:上面的静态代理和动态代理模式都是要求目标对象是实现一个接口的目标对象,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理。
Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.
因为这个代理我之前都没听过,而且觉得挺抽象的,还有点没看懂,所以就不班门弄斧了,直接贴上一个我觉得关于代理模式说的比较全的一个帖子:https://www.cnblogs.com/qlqwjy/p/7550609.html

至此,Dubbo中比较经典的 几个设计模式的使用就到这里了,肯定是说的不全,但是那么大的框架也没那个精力一一介绍,所以这篇文章就到这里了,如果稍微帮到你了记得点个喜欢点个关注,也祝大家工作顺顺利利,生活健健康康!新年快乐,万事如意!

推荐阅读更多精彩内容