動態

詳情 返回 返回

《進大廠前先學會閲讀源碼》之shenyu網關-替換ZooKeeper客户端 - 動態 詳情

相信大家碰到源碼一開始都是比較無從下手的🙃,不知道從哪開始閲讀,面對大量代碼暈頭轉向,索性就讀不下去了,又浪費了一次提升自己的機會😭。

我認為有一種方法,可以解決大家的困擾!那就是通過閲讀某一次開源【commit】、某一次社區【ISSUE】,從這個入口出發去閲讀源碼!!

至此,我們發現自己開始從大量堆砌的源碼中脱離開來😀。豁然開朗,柳暗花明又一村🍀。

一、前瞻

今天我們攻克的一次開源提交:commit鏈接

本次commit的核心內容就在下圖紅框中,意思很清晰明瞭:替換當前的ZooKeeper客户端。

在這裏插入圖片描述

看看Magic Header是什麼

Magic Header 通常指的是文件開頭的一段特定字節序列,用來標識或確認文件的格式和類型。這些字節序列是預先定義的,不同的文件格式有不同的 Magic Header。操作系統和應用程序通過讀取這些特定的字節序列來識別文件的格式,即使文件擴展名被更改或丟失。

簡單來説就是用來標識文件。

我們先整體看下本次所有提交的內容,雖然看起來涉及了大量的模塊、大量的代碼,但核心其實就是紅框對應的內容。既然是要替換當前的ZooKeeper客户端,那便是要新建Curator這個新的客户端,同時修改調用端的調用對象!
在這裏插入圖片描述

下面我們就來看看貢獻者是怎麼實現替換的!!同時上文提到並將數據保存在沒有 magic header 的 zk 中,正確翻譯應該是保存數據在zk時,不使用magic header來標識數據,那他又是怎麼做的??

二、探索

我們參照上圖,先看下ZookeeperClient類,該類很顯眼的引入了本次提交的主角CuratorFramework,ZookeeperClient封裝了CuratorFramework作為ZooKeeper新的客户端。

public class ZookeeperClient {

    private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperClient.class);

    private final ZookeeperConfig config;

    private final CuratorFramework client;

    private final Map<String, CuratorCache> caches = new ConcurrentHashMap<>();

    public ZookeeperClient(final ZookeeperConfig zookeeperConfig) {
        this.config = zookeeperConfig;
        ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(config.getBaseSleepTimeMilliseconds(), config.getMaxRetries(), config.getMaxSleepTimeMilliseconds());

        CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder()
                .connectString(config.getServerLists())
                .retryPolicy(retryPolicy)
                .connectionTimeoutMs(config.getConnectionTimeoutMilliseconds())
                .sessionTimeoutMs(config.getSessionTimeoutMilliseconds())
                .namespace(config.getNamespace());

        if (!StringUtils.isEmpty(config.getDigest())) {
            builder.authorization("digest", config.getDigest().getBytes(StandardCharsets.UTF_8));
        }

        this.client = builder.build();
    }

    /**
     * start.
     */
    public void start() {
        this.client.start();
        try {
            this.client.blockUntilConnected();
        } catch (InterruptedException e) {
            LOGGER.warn("Interrupted during zookeeper client starting.");
            Thread.currentThread().interrupt();
        }
    }
}

而ZookeeperInstanceRegisterRepository就是起到控制器的作用,把ZookeeperConfig類的配置註冊到ZookeeperClient來初始化我們新的客户端

我們在代碼可以看到初始化方法init()。

@Join
public class ZookeeperInstanceRegisterRepository implements ShenyuInstanceRegisterRepository {

    private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperInstanceRegisterRepository.class);

    private ZookeeperClient client;

    private final Map<String, String> nodeDataMap = new HashMap<>();

    @Override
    public void init(final InstanceConfig config) {
        Properties props = config.getProps();
        int sessionTimeout = Integer.parseInt(props.getProperty("sessionTimeout", "3000"));
        int connectionTimeout = Integer.parseInt(props.getProperty("connectionTimeout", "3000"));

        int baseSleepTime = Integer.parseInt(props.getProperty("baseSleepTime", "1000"));
        int maxRetries = Integer.parseInt(props.getProperty("maxRetries", "3"));
        int maxSleepTime = Integer.parseInt(props.getProperty("maxSleepTime", String.valueOf(Integer.MAX_VALUE)));

        ZookeeperConfig zkConfig = new ZookeeperConfig(config.getServerLists());
        zkConfig.setBaseSleepTimeMilliseconds(baseSleepTime)
                .setMaxRetries(maxRetries)
                .setMaxSleepTimeMilliseconds(maxSleepTime)
                .setSessionTimeoutMilliseconds(sessionTimeout)
                .setConnectionTimeoutMilliseconds(connectionTimeout);

        String digest = props.getProperty("digest");
        if (!StringUtils.isEmpty(digest)) {
            zkConfig.setDigest(digest);
        }

        this.client = new ZookeeperClient(zkConfig);
        this.client.getClient().getConnectionStateListenable().addListener((c, newState) -> {
            if (newState == ConnectionState.RECONNECTED) {
                nodeDataMap.forEach((k, v) -> {
                    if (!client.isExist(k)) {
                        client.createOrUpdate(k, v, CreateMode.EPHEMERAL);
                        LOGGER.info("zookeeper client register instance success: {}", v);
                    }
                });
            }
        });

        client.start();
    }
}

替換客户端的操作其實不會太複雜,主要就是把所有舊的客户端入參修改為新的客户端對象,可以看下貢獻者的提交代碼。
在這裏插入圖片描述

我們打開commit鏈接指向的ISSUE

在這裏插入圖片描述
意思其實是舊的zkClient保存數據時默認會把magic header頭信息插入到數據中,導致了我們的序列化數據失敗

而貢獻者本次提交把客户端改為了Curator客户端,也就不會有上面插入magic header頭信息的操作了。

大家能否感受通過commit、ISSUE這種方式來閲讀源碼的樂趣呢!

<br/>

創作不易,不妨點贊、關注、收藏支持一下,各位的支持就是我創作的最大動力❤️

Add a new 評論

Some HTML is okay.