【Curator NodeCache 源碼解析】

NodeCache

  1. NodeCache在new對象時候會調用client.newWatcherRemoveCuratorFramework去新建一個監聽客戶端。
  /**
     * @param client curztor client
     * @param path the full path to the node to cache
     * @param dataIsCompressed if true, data in the path is compressed
     */
    public NodeCache(CuratorFramework client, String path, boolean dataIsCompressed)
    {
        this.client = client.newWatcherRemoveCuratorFramework();
        this.path = PathUtils.validatePath(path);
        this.dataIsCompressed = dataIsCompressed;
    }

  1. start() 啓動緩存服務
 public void     start(boolean buildInitial) throws Exception
    {
      //設值啓動狀態
       Preconditions.checkState(state.compareAndSet(State.LATENT,              State.STARTED), "Cannot be started more than once");

      //增加連接狀態監聽 client.getConnectionStateListenable().addListener(connectionStateListener);
    // 進行初始化操作
        if ( buildInitial )
        {
            client.checkExists().creatingParentContainersIfNeeded().forPath(path);
            internalRebuild();
        }
        reset();
    }
    // 判斷是否是啓動連接狀態,判斷節點是否存在
   private void     reset() throws Exception
    {
        if ( (state.get() == State.STARTED) && isConnected.get() )
        {
            client.checkExists().creatingParentContainersIfNeeded().usingWatcher(watcher).inBackground(backgroundCallback).forPath(path);
        }
    }

在reset()方法中傳入了兩個對象,一個監聽對象watcher,一個是回調對象backgroundCallback(異步回調)
剛開始啓動會註冊一個watcher對象,當服務器返回數據回來時候會調用回調函數

  private void processBackgroundResult(CuratorEvent event) throws Exception
    {
        // 當發生獲取數據或者是判斷節點是否存在時候進行監聽
        switch ( event.getType() )
        {
            case GET_DATA:
                 // 響應狀態爲ok時,將刷新本地緩存的數據
                if ( event.getResultCode() == KeeperException.Code.OK.intValue() )
                {   // 獲取監聽到的數據變動集合
                    ChildData childData = new ChildData(path, event.getStat(), event.getData());
                    // 刷新本地緩存數據
                    setNewData(childData);
                }
                break;
            }

            case EXISTS:
            {
                if ( event.getResultCode() == KeeperException.Code.NONODE.intValue() )
                {
                    setNewData(null);
                }
                else if ( event.getResultCode() == KeeperException.Code.OK.intValue() )
                {
                    if ( dataIsCompressed )
                    {
                        client.getData().decompressed().usingWatcher(watcher).inBackground(backgroundCallback).forPath(path);
                    }
                    else
                    {
                        client.getData().usingWatcher(watcher).inBackground(backgroundCallback).forPath(path);
                    }
                }
                break;
            }
        }

刷新本地緩存數據,觸發監聽

   //private final ListenerContainer<NodeCacheListener> listeners 監聽容器集合
  private void setNewData(ChildData newData) throws InterruptedException
    {   
        // data 緩存對象,getAndSet 設置新值並返回舊值
        ChildData   previousData = data.getAndSet(newData);
        // 兩個對象不一致時,觸發監聽
        if ( !Objects.equal(previousData, newData) )
        {
            // 將本地的監聽容器循環
            listeners.forEach
            (   // 將監聽對象作爲參數傳入給foreach方法,之後方法裏會調用
                new Function<NodeCacheListener, Void>()
                {
                    @Override
                    public Void apply(NodeCacheListener listener)
                    {
                        try
                        {
                            listener.nodeChanged();
                        }
                        catch ( Exception e )
                        {
                            ThreadUtils.checkInterrupted(e);
                            log.error("Calling listener", e);
                        }
                        return null;
                    }
                }
            );

            if ( rebuildTestExchanger != null )
            {
                try
                {
                    rebuildTestExchanger.exchange(new Object());
                }
                catch ( InterruptedException e )
                {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }
    

 //接口方法Function<F,T> F是參數 T是返回值
@GwtCompatible
public interface Function<F, T> {
    @Nullable
    @CanIgnoreReturnValue
    T apply(@Nullable F var1);

    boolean equals(@Nullable Object var1);
}
    // ListenerContainer 監聽容器裏foreach方法,循環調用每一個監聽器
  /**
     * Utility - apply the given function to each listener. The function receives
     * the listener as an argument.
     *
     * @param function function to call for each listener
     */
    public void     forEach(final Function<T, Void> function)
    {
        for ( final ListenerEntry<T> entry : listeners.values() )
        {
            entry.executor.execute
            (
                new Runnable()
                {
                    @Override
                    public void run()
                    {
                        try
                        {
                            function.apply(entry.listener);
                        }
                        catch ( Throwable e )
                        {
                            ThreadUtils.checkInterrupted(e);
                            log.error(String.format("Listener (%s) threw an exception", entry.listener), e);
                        }
                    }
                }
            );
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章