Dubbo中用到了哪些设计模式?

开发 前端
当工厂想提供更多产品时,还得对创建过程进行修改,因此抽象出一个工厂类,当增加一种产品,就增加一个工厂类(继承抽象工厂类或实现接口)。

[[404370]]

介绍

策略模式

这个毫无争议,Dubbo是基于SPI来扩展的,SPI就是典型的策略模式。

Dubbo中可替换的组件太多了,例如负载均衡策略

实现类 解释
RandomLoadBalance 随机策略(默认)
RoundRobinLoadBalance 轮询策略
LeastActiveLoadBalance 最少活跃调用数
ConsistentHashLoadBalance 一致性hash策略

工厂模式

「简单工厂模式」:提供一个方法,返回创建好的对象

  1. public class VideoFactory { 
  2.  
  3.     public static Video getVideo(String type) { 
  4.         if ("java".equalsIgnoreCase(type)) { 
  5.             return new JavaVideo(); 
  6.         } else if ("python".equalsIgnoreCase(type)) { 
  7.             return new PythonVideo(); 
  8.         } 
  9.         return null
  10.     } 

「工厂方法模式」:当工厂想提供更多产品时,还得对创建过程进行修改,因此抽象出一个工厂类,当增加一种产品,就增加一个工厂类(继承抽象工厂类或实现接口)。这样就实现了对扩展开发,对修改关闭

  1. public abstract class VideoFactory { 
  2.  
  3.     public abstract Video getVideo(); 
  4. public class JavaVideoFactory extends VideoFactory { 
  5.     public Video getVideo() { 
  6.         return new JavaVideo(); 
  7.     } 
  8. public class Test { 
  9.  
  10.     public static void main(String[] args) { 
  11.         VideoFactory videoFactory = new JavaVideoFactory(); 
  12.         Video video = videoFactory.getVideo(); 
  13.         // 学习Java视频 
  14.         video.study(); 
  15.     } 

「抽象工厂模式」:当生产的产品较多时,如果我们用工厂方法模式会造成类爆照,此时我们就可以把相关的产品生产放到一个工厂类中

  1. public abstract class CourseFactory { 
  2.  
  3.     public abstract Video getVideo(); 
  4.     public abstract Article getArticle(); 
  5. public class JavaCourseFactory extends CourseFactory { 
  6.     public Video getVideo() { 
  7.         return new JavaVideo(); 
  8.     } 
  9.  
  10.     public Article getArticle() { 
  11.         return new JavaArticle(); 
  12.     } 

因为JavaVideo和JavaArticle都是Java相关的资料,所以可以用一个工厂类来生产。如果用工厂方法模式来设计的话,JavaVideo和JavaArticle都会有一个对应的工厂类

简单工厂模式

  1. public class LoggerFactory { 
  2.  
  3.     public static Logger getLogger(Class<?> key) { 
  4.         return LOGGERS.computeIfAbsent(key.getName(), name -> new FailsafeLogger(LOGGER_ADAPTER.getLogger(name))); 
  5.     } 

工厂方法模式

Dubbo可以对结果进行缓存,缓存的策略有很多种,一种策略对应一个缓存工厂类

  1. @SPI("lru"
  2. public interface CacheFactory { 
  3.  
  4.     @Adaptive("cache"
  5.     Cache getCache(URL url, Invocation invocation); 
  6.  

抽象工厂模式

在RPC框架中,客户端发送请求和服务端执行请求的过程都是由代理类来完成的。客户端的代理对象叫做Client Stub,服务端的代理对象叫做Server Stub。

  1. @SPI("javassist"
  2. public interface ProxyFactory { 
  3.  
  4.     // 针对consumer端,创建出代理对象 
  5.     @Adaptive({Constants.PROXY_KEY}) 
  6.     <T> T getProxy(Invoker<T> invoker) throws RpcException; 
  7.  
  8.     // 针对consumer端,创建出代理对象 
  9.     @Adaptive({Constants.PROXY_KEY}) 
  10.     <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException; 
  11.  
  12.     // 针对provider端,将服务对象包装成一个Invoker对象 
  13.     @Adaptive({Constants.PROXY_KEY}) 
  14.     <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException; 
  15.  

单例模式

服务导出的过程中,为了防止开启多个NettyServer,用了单例模式

  1. private void openServer(URL url) { 
  2.     // find server. 
  3.     String key = url.getAddress(); 
  4.     //client can export a service which's only for server to invoke 
  5.     boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true); 
  6.     if (isServer) { 
  7.         ExchangeServer server = serverMap.get(key); 
  8.         if (server == null) { 
  9.             synchronized (this) { 
  10.                 server = serverMap.get(key); 
  11.                 if (server == null) { 
  12.                     // 创建服务器实例 
  13.                     serverMap.put(key, createServer(url)); 
  14.                 } 
  15.             } 
  16.         } else { 
  17.             // server supports reset, use together with override 
  18.             server.reset(url); 
  19.         } 
  20.     } 

装饰者模式

Dubbo中网络传输层用到了Netty,当我们用Netty开发时,一般都是写多个ChannelHandler,然后将这些ChannelHandler添加到ChannelPipeline上,就是典型的责任链模式

但是Dubbo考虑到有可能替换网络框架组件,所以整个请求发送和请求接收的过程全部用的都是装饰者模式。即只有NettyServerHandler实现的接口是Netty中的ChannelHandler,剩下的接口实现的是Dubbo中的ChannelHandler

如下是服务端消息接收会经过的ChannelHandler

代理模式

前面说过了哈,Client Stub和Server Stub都是代理对象

适配器模式

Dubbo可以支持多个日志框架,每个日志框架的实现都有对应的Adapter类,为什么要搞Adapter类呢,因为Dubbo中日志接口Logger用的是自己的,而实现类是引入的。但这些日志实现类的等级和Dubbo中定义的日志等级并不完全一致,例如JdkLogger中并没有trace和debug这个等级,所以要用Adapter类把Logger中的等级对应到实现类中的合适等级

  1. public interface Logger 
  2.  
  3.     // 省略部分代码 
  4.      
  5.     void trace(String msg); 
  6.  
  7.     void debug(String msg); 
  8.  
  9.     void info(String msg); 
  10.  
  11.     void warn(String msg); 
  12.  

Dubbo接口中定义的日志等级 JdkLogger对应的日志等级 Slf4jLogger对应的日志等级
trace finer trace
debug finer debug
info info info

观察者模式

在Dubbo中提供了各种注册中心的实现,类图如下。AbstractRegistry对注册中心的内容进行了缓存,这样能保证当注册中心不可用的时候,还能正常提供服务

「既然对注册中心的内容进行了缓存,那么注册中心的内容发生改变的时候,怎么通知客户端呢?」

例如客户端从注册中心获取到服务端的地址,并缓存到本地,如果服务端宕机了,本地缓存怎么清除呢?此时就得需要对有可能变动的节点进行订阅。当节点发生变化的时候,就能收到通知,这样就能更新本地缓存。

NotifyListener就是接收节点变动的接口,各种注册中心的节点发生变化都会主动回调这个接口

  1. public interface RegistryService { 
  2.  
  3.     // 注册 
  4.     void register(URL url); 
  5.  
  6.     // 注销 
  7.     void unregister(URL url); 
  8.  
  9.     // 订阅,订阅的数据发生变化,会主动通知NotifyListener#notify方法 
  10.     void subscribe(URL url, NotifyListener listener); 
  11.  
  12.     // 退订 
  13.     void unsubscribe(URL url, NotifyListener listener); 
  14.  
  15.     // 查找服务地址 
  16.     List<URL> lookup(URL url); 
  17.  

责任链模式

代理对象(Client Stub或者Server Stub)在执行的过程中会执行所有Filter的invoke方法,但是这个实现方法是对对象不断进行包装,看起来非常像装饰者模式,但是基于方法名和这个Filter的功能,我更觉得这个是责任链模式

  1. private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) { 
  2.     Invoker<T> last = invoker; 
  3.     // 获取自动激活的扩展类 
  4.     List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), keygroup); 
  5.     if (!filters.isEmpty()) { 
  6.         for (int i = filters.size() - 1; i >= 0; i--) { 
  7.             final Filter filter = filters.get(i); 
  8.             final Invoker<T> next = last
  9.             last = new Invoker<T>() { 
  10.  
  11.                 // 省略部分代码 
  12.  
  13.                 @Override 
  14.                 public Result invoke(Invocation invocation) throws RpcException { 
  15.                     // filter 不断的套在 Invoker 上,调用invoke方法的时候就会执行filter的invoke方法 
  16.                     Result result = filter.invoke(next, invocation); 
  17.                     if (result instanceof AsyncRpcResult) { 
  18.                         AsyncRpcResult asyncResult = (AsyncRpcResult) result; 
  19.                         asyncResult.thenApplyWithContext(r -> filter.onResponse(r, invoker, invocation)); 
  20.                         return asyncResult; 
  21.                     } else { 
  22.                         return filter.onResponse(result, invoker, invocation); 
  23.                     } 
  24.                 } 
  25.  
  26.             }; 
  27.         } 
  28.     } 
  29.     return last

本文转载自微信公众号「Java识堂」,可以通过以下二维码关注。转载本文请联系Java识堂公众号。

 

责任编辑:武晓燕 来源: Java识堂
相关推荐

2022-09-21 09:01:27

Spring设计模式框架,

2023-07-11 08:50:34

2020-03-18 09:43:37

开发技能代码

2019-05-29 17:20:07

Spring设计模式Java

2021-05-31 07:58:59

Spring设计模式

2020-01-02 15:43:29

Spring设计策略

2021-10-27 17:57:35

设计模式场景

2023-10-04 07:27:33

WebPhotoshop

2021-08-11 17:22:11

设计模式单例

2010-05-11 14:23:05

Unix命令

2011-09-08 16:30:59

SQL Server查询

2021-02-15 22:07:18

项目策略模式

2010-04-02 10:04:21

Oracle结构

2019-11-07 11:49:14

架构运维技术

2021-10-29 09:40:21

设计模式软件

2022-05-16 08:09:45

前端API

2019-04-24 09:43:46

代码开发工具

2023-11-06 12:44:00

物联网传感器

2022-05-13 08:18:51

物联网新兴技术IOT

2021-05-06 09:06:12

Vue Router组件视图
点赞
收藏

51CTO技术栈公众号