Dubbo運行原理

1、SOA模式
  首先簡單介紹一下SOA模式,這對咱們後面理解Dubbo頗有幫助。數據庫

  SOA模式是什麼?編程

  SQA(Service-Oriented Architecture)即面向服務架構,它將應用程序的不一樣功能單元(這裏就理解爲服務)進行了拆分。在這種架構下項目不會直接和數據庫進行交互,而是經過調用不一樣服務的接口來訪問數據庫。設計模式

  模式優勢在哪?架構

  這樣最直接的好處就是解決代碼冗餘,若是多個項目同時都要訪問數據庫同一張表。好比用戶表的訪問。咱們能夠直接調用用戶服務裏面的接口進行開發,而不須要每一個項目都去寫一遍用戶表的增刪改查。除了這個,SOA能帶給咱們的好處就是可以讓開發者以更迅速、更可靠、更具重用性架構整個業務系統。較之以往MVC開發模式,以SOA架構的系統可以更加從容地面對業務的急劇變化。框架

  SOA示意圖:ide

clipboard.png

2、Dubbo基本組成
  聊完了SOA,如今來看看Dubbo內部架構,相信你們多多少少看過下面這幅圖:源碼分析

@Override
    protected void doSubscribe(final URL url, final NotifyListener listener) {
        try {
            if (Constants.ANY_VALUE.equals(url.getServiceInterface())) {//根據URL獲得服務接口爲*,也就是全部
                String root = toRootPath();
                ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url);//拿取URL下的監聽器
                if (listeners == null) {//不存在則進行建立
                    zkListeners.putIfAbsent(url, new ConcurrentHashMap<NotifyListener, ChildListener>());
                    listeners = zkListeners.get(url);
                }
                ChildListener zkListener = listeners.get(listener);//獲得子目錄的監聽器
                if (zkListener == null) {//沒法獲得子目錄監聽器,則會新建一個。
                    listeners.putIfAbsent(listener, new ChildListener() {
                        @Override
                        public void childChanged(String parentPath, List<String> currentChilds) {
                            for (String child : currentChilds) {
                                child = URL.decode(child);
                                if (!anyServices.contains(child)) {
                                    anyServices.add(child);
                                    //若是consumer的interface爲*,會訂閱每個url,會觸發另外一個分支的邏輯
                                    //這裏是用來對/dubbo下面提供者新增時的回調,至關於增量
                                    subscribe(url.setPath(child).addParameters(Constants.INTERFACE_KEY, child,
                                            Constants.CHECK_KEY, String.valueOf(false)), listener);
                                }
                            }
                        }
                    });
                    zkListener = listeners.get(listener);
                }
                zkClient.create(root, false);
                //添加監聽器會返回子節點集合
                List<String> services = zkClient.addChildListener(root, zkListener);//訂閱root目錄下的子元素,好比:/dubbo/com.learnDubbo.demo.DemoService/providers
                if (services != null && !services.isEmpty()) {
                    for (String service : services) {
                        service = URL.decode(service);
                        anyServices.add(service);
                        subscribe(url.setPath(service).addParameters(Constants.INTERFACE_KEY, service,
                                Constants.CHECK_KEY, String.valueOf(false)), listener);
                    }
                }
            } else {
                //這邊是針對明確interface的訂閱邏輯
                List<URL> urls = new ArrayList<URL>();
                //針對每種category路徑進行監聽
                for (String path : toCategoriesPath(url)) {
                    ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url);
                    if (listeners == null) {
                        zkListeners.putIfAbsent(url, new ConcurrentHashMap<NotifyListener, ChildListener>());
                        listeners = zkListeners.get(url);
                    }
                    ChildListener zkListener = listeners.get(listener);
                    if (zkListener == null) {
                        //封裝回調邏輯
                        listeners.putIfAbsent(listener, new ChildListener() {
                            @Override
                            public void childChanged(String parentPath, List<String> currentChilds) {
                                ZookeeperRegistry.this.notify(url, listener, toUrlsWithEmpty(url, parentPath, currentChilds));
                            }
                        });
                        zkListener = listeners.get(listener);
                    }
                    //建立節點
                    zkClient.create(path, false);
                    //增長回調
                    List<String> children = zkClient.addChildListener(path, zkListener);
                    if (children != null) {
                        urls.addAll(toUrlsWithEmpty(url, path, children));
                    }
                }
                //而且會對訂閱的URL下的服務進行監聽,並會實時的更新Consumer中的invoke列表,使得可以進行調用。這個方法不展開講
                notify(url, listener, urls);
            }
        } catch (Throwable e) {
            throw new RpcException("Failed to subscribe " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }

四、invoke:根據獲取到的Provider地址,真實調用Provider中功能。這裏就是惟一一個同步的方法,由於消費者要獲得生產者傳來的數據才能進行下一步操做,可是Dubbo是一個RPC框架,RPC的核心就在於只能知道接口不能知道內部具體實現。因此在Consumer方使用了代理設計模式,建立一個Provider方類的一個代理對象,經過代理對象獲取Provider中真實功能,起到保護Provider真實功能的做用。學習

  invoke部分源碼分析this

  有興趣的能夠看看invoke調用過程url

  五、Monitor:Consumer和Provider每隔1分鐘向Monitor發送統計信息,統計信息包含,訪問次數,頻率等

4、總結  這裏只是稍微對Dubbo的原理作了一下分析,想要弄懂Dubbo還須要結合源碼來看。儘管不少時候咱們只是一個使用者,可是可以理解內部運行原理不但可以讓咱們更好的使用,同時裏面的編程思路,設計模式也是咱們須要學習的。後面還會作更多關於Dubbo的原理解析。

相關文章
相關標籤/搜索