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

专注于为中小企业提供网站设计、成都做网站服务,电脑端+手机端+微信端的三站合一,更高效的管理,为中小企业乌当免费做网站提供优质的服务。我们立足成都,凝聚了一批互联网行业人才,有力地推动了近1000家企业的稳健成长,帮助中小企业通过网站建设实现规模扩充和转变。
Dubbo中可替换的组件太多了,例如负载均衡策略
| 实现类 | 解释 | 
|---|---|
| RandomLoadBalance | 随机策略(默认) | 
| RoundRobinLoadBalance | 轮询策略 | 
| LeastActiveLoadBalance | 最少活跃调用数 | 
| ConsistentHashLoadBalance | 一致性hash策略 | 
「简单工厂模式」:提供一个方法,返回创建好的对象
- public class VideoFactory {
 - public static Video getVideo(String type) {
 - if ("java".equalsIgnoreCase(type)) {
 - return new JavaVideo();
 - } else if ("python".equalsIgnoreCase(type)) {
 - return new PythonVideo();
 - }
 - return null;
 - }
 - }
 
「工厂方法模式」:当工厂想提供更多产品时,还得对创建过程进行修改,因此抽象出一个工厂类,当增加一种产品,就增加一个工厂类(继承抽象工厂类或实现接口)。这样就实现了对扩展开发,对修改关闭
- public abstract class VideoFactory {
 - public abstract Video getVideo();
 - }
 - public class JavaVideoFactory extends VideoFactory {
 - public Video getVideo() {
 - return new JavaVideo();
 - }
 - }
 - public class Test {
 - public static void main(String[] args) {
 - VideoFactory videoFactory = new JavaVideoFactory();
 - Video video = videoFactory.getVideo();
 - // 学习Java视频
 - video.study();
 - }
 - }
 
「抽象工厂模式」:当生产的产品较多时,如果我们用工厂方法模式会造成类爆照,此时我们就可以把相关的产品生产放到一个工厂类中
- public abstract class CourseFactory {
 - public abstract Video getVideo();
 - public abstract Article getArticle();
 - }
 - public class JavaCourseFactory extends CourseFactory {
 - public Video getVideo() {
 - return new JavaVideo();
 - }
 - public Article getArticle() {
 - return new JavaArticle();
 - }
 - }
 
因为JavaVideo和JavaArticle都是Java相关的资料,所以可以用一个工厂类来生产。如果用工厂方法模式来设计的话,JavaVideo和JavaArticle都会有一个对应的工厂类
简单工厂模式
- public class LoggerFactory {
 - public static Logger getLogger(Class> key) {
 - return LOGGERS.computeIfAbsent(key.getName(), name -> new FailsafeLogger(LOGGER_ADAPTER.getLogger(name)));
 - }
 - }
 
工厂方法模式
Dubbo可以对结果进行缓存,缓存的策略有很多种,一种策略对应一个缓存工厂类
- @SPI("lru")
 - public interface CacheFactory {
 - @Adaptive("cache")
 - Cache getCache(URL url, Invocation invocation);
 - }
 
抽象工厂模式
在RPC框架中,客户端发送请求和服务端执行请求的过程都是由代理类来完成的。客户端的代理对象叫做Client Stub,服务端的代理对象叫做Server Stub。
- @SPI("javassist")
 - public interface ProxyFactory {
 - // 针对consumer端,创建出代理对象
 - @Adaptive({Constants.PROXY_KEY})
 T getProxy(Invoker invoker) throws RpcException; - // 针对consumer端,创建出代理对象
 - @Adaptive({Constants.PROXY_KEY})
 T getProxy(Invoker invoker, boolean generic) throws RpcException; - // 针对provider端,将服务对象包装成一个Invoker对象
 - @Adaptive({Constants.PROXY_KEY})
 Invoker getInvoker(T proxy, Class type, URL url) throws RpcException; - }
 
服务导出的过程中,为了防止开启多个NettyServer,用了单例模式
- private void openServer(URL url) {
 - // find server.
 - String key = url.getAddress();
 - //client can export a service which's only for server to invoke
 - boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true);
 - if (isServer) {
 - ExchangeServer server = serverMap.get(key);
 - if (server == null) {
 - synchronized (this) {
 - server = serverMap.get(key);
 - if (server == null) {
 - // 创建服务器实例
 - serverMap.put(key, createServer(url));
 - }
 - }
 - } else {
 - // server supports reset, use together with override
 - server.reset(url);
 - }
 - }
 - }
 
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中的等级对应到实现类中的合适等级
- public interface Logger
 - // 省略部分代码
 - void trace(String msg);
 - void debug(String msg);
 - void info(String msg);
 - void warn(String msg);
 - }
 
| Dubbo接口中定义的日志等级 | JdkLogger对应的日志等级 | Slf4jLogger对应的日志等级 | 
|---|---|---|
| trace | finer | trace | 
| debug | finer | debug | 
| info | info | info | 
在Dubbo中提供了各种注册中心的实现,类图如下。AbstractRegistry对注册中心的内容进行了缓存,这样能保证当注册中心不可用的时候,还能正常提供服务
「既然对注册中心的内容进行了缓存,那么注册中心的内容发生改变的时候,怎么通知客户端呢?」
例如客户端从注册中心获取到服务端的地址,并缓存到本地,如果服务端宕机了,本地缓存怎么清除呢?此时就得需要对有可能变动的节点进行订阅。当节点发生变化的时候,就能收到通知,这样就能更新本地缓存。
NotifyListener就是接收节点变动的接口,各种注册中心的节点发生变化都会主动回调这个接口
- public interface RegistryService {
 - // 注册
 - void register(URL url);
 - // 注销
 - void unregister(URL url);
 - // 订阅,订阅的数据发生变化,会主动通知NotifyListener#notify方法
 - void subscribe(URL url, NotifyListener listener);
 - // 退订
 - void unsubscribe(URL url, NotifyListener listener);
 - // 查找服务地址
 - List
 lookup(URL url); - }
 
代理对象(Client Stub或者Server Stub)在执行的过程中会执行所有Filter的invoke方法,但是这个实现方法是对对象不断进行包装,看起来非常像装饰者模式,但是基于方法名和这个Filter的功能,我更觉得这个是责任链模式
- private static
 Invoker buildInvokerChain(final Invoker invoker, String key, String group) { - Invoker
 last = invoker; - // 获取自动激活的扩展类
 - List
 filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group); - if (!filters.isEmpty()) {
 - for (int i = filters.size() - 1; i >= 0; i--) {
 - final Filter filter = filters.get(i);
 - final Invoker
 next = last; - last = new Invoker
 () { - // 省略部分代码
 - @Override
 - public Result invoke(Invocation invocation) throws RpcException {
 - // filter 不断的套在 Invoker 上,调用invoke方法的时候就会执行filter的invoke方法
 - Result result = filter.invoke(next, invocation);
 - if (result instanceof AsyncRpcResult) {
 - AsyncRpcResult asyncResult = (AsyncRpcResult) result;
 - asyncResult.thenApplyWithContext(r -> filter.onResponse(r, invoker, invocation));
 - return asyncResult;
 - } else {
 - return filter.onResponse(result, invoker, invocation);
 - }
 - }
 - };
 - }
 - }
 - return last;
 - }
 
本文转载自微信公众号「Java识堂」,可以通过以下二维码关注。转载本文请联系Java识堂公众号。
                标题名称:Dubbo中用到了哪些设计模式?
                
                URL分享:http://www.csdahua.cn/qtweb/news31/24931.html
            
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网