美文网首页
Dubbo与设计模式之一 注册中心

Dubbo与设计模式之一 注册中心

作者: 北交吴志炜 | 来源:发表于2020-12-27 18:47 被阅读0次

    业务程序员在各种需求与业务压力的驱动下,非常容易沦为crud if else选手。
    解脱之法就是多看别人的优秀代码,取其精华,知行合一,把自己的代码写优秀。
    本文所有的代码均源自于dubbo 2.7.5 版本

    工厂方法

    Dubbo支持Service粒度的多注册中心,早期大家最常用的是zookeeper,后续又有redis,nacos,etcd等等,还在持续扩展中,不同注册中心,关于网络初始化,服务注册,服务摘除,订阅等,背后的处理逻辑都不同。
    那么dubbo是如何实现的呢?见下图

    工厂方法

    dubbo使用了工厂方法模式。对于不同的注册中心实例,由其对应的Factory工厂类来负责创建。dubbo启动时,根据配置文件中指定的注册中心种类,基于[dubbo spi机制] (https://www.jianshu.com/p/d4d7ebc8f7bb),进行RegistryFactory的初始化,以及对应Registry的创建。

    以zookeeper注册中心为例,配置见下

    dubbo.registry.address=zookeeper://${zookeeper.addres}:2181
    

    启动时,将配置加载为Url对象后,protocal即为zookeeper,dubbo spi会根据META-INF文件夹下
    org.apache.dubbo.registry文件中配置的实现类,去找到对应的工厂实现,进行初始化。

    zookeeper=org.apache.dubbo.registry.zookeeper.ZookeeperRegistryFactory
    redis=org.apache.dubbo.registry.redis.RedisRegistryFactory
    nacos=org.apache.dubbo.registry.nacos.NacosRegistryFactory
    ...
    

    当需要拓展新的注册中心时,只需要按照规范去新增Registry实现,对应的工厂RegistryFactory实现,配置文件增加一条记录即可,原有代码可以做到一行都不改,完美满足开闭原则。

    模板方法

    不同的注册中心工厂,他们初始化Registry的逻辑不同,但是创建完毕后,存储Registry的数据结构,获取Registry,清除Registry等的流程和逻辑是相同的。dubbo在此处使用了模板方法模式,所有的工厂去继承AbstractRegistryFactory,复用父类的数据结构和其他的公有逻辑,自己仅实现createRegistry()的个性化部分。见下图

    模板方法

    模板方法在技术上满足开闭原则,在业务上,可以把流程规范化,把风险控制在最小范围,很多时候,我们接手一个历史项目的时候,如果面对堆砌出来的代码逻辑,我们一般是不太敢动的,风险实在不可控,如果是基于模板方法设计的逻辑,那么我们其实是有底的,风险和测试边界都是相对可控的。

    代理模式

    看起来dubbo注册中心的初始化,就是通过RegistryFactory生产Registry的过程,但是dubbo在这里预埋了一批钩子,以支持Registry在register,unregister,subscribe,unsubscribe等事件发生的时候,触发一些操作(RegistryServiceListener),实现方式是代理模式(动态代理),见下图

    动态代理

    标红部分,引入了RegistryFactoryWrapper和ListenerRegistryWrapper两个代理类。
    其中RegistryFactoryWrapper这个代理类,代理逻辑即通过SPI初始化RegistryServiceListener,然后把这些RegistryServiceListener塞到ListenerRegistryWrapper中。

    public Registry getRegistry(URL url) {
            return new ListenerRegistryWrapper(registryFactory.getRegistry(url),
                    Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(RegistryServiceListener.class)
                            .getActivateExtension(url, "registry.listeners")));
        }
    

    ListenerRegistryWrapper代理类,主要的代理逻辑也很简单,遍历RegistryServiceListener,执行对应的事件监听方法。

    public void register(URL url) {
            try {
                registry.register(url);
            } finally {
                if (CollectionUtils.isNotEmpty(listeners)) {
                    RuntimeException exception = null;
                    for (RegistryServiceListener listener : listeners) {
                        if (listener != null) {
                            try {
                                listener.onRegister(url);
                            } catch (RuntimeException t) {
                                logger.error(t.getMessage(), t);
                                exception = t;
                            }
                        }
                    }
                    if (exception != null) {
                        throw exception;
                    }
                }
            }
    

    那么饶了这么一大圈,在Factory和Register这两层都加上代理之后,这个RegistryServiceListener都起了什么作用呢?答案是什么实际作用都没有,以2.7.5版本代码为例,代码并未初始化任何RegistryServiceListener的实现,这两层代理只是为了把执行Listener的路铺好,目前并未有任何车在上面跑,这里可以看到dubbo团队为了支撑扩展性,在这些细节处,也算是费劲心机了。

    Dubbo与设计模式之二 filter机制

    相关文章

      网友评论

          本文标题:Dubbo与设计模式之一 注册中心

          本文链接:https://www.haomeiwen.com/subject/ewaonktx.html