服务大量配置信息使用ZOOKEEPER和jvm 缓存实现

本文介绍如何使用ZooKeeper进行配置管理,通过Curator框架实现配置的读取、监听及更新,确保各客户端能实时同步最新的配置信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

设置更改配置信息写入zookeeper,同时通知各个客户端更新配置信息到jvm 缓存。获取配置信息从jvm缓存获取。


一:pom 依赖

<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>2.12.0</version>
</dependency>

二:java 代码实现


监听类:

import com.alibaba.fastjson.JSON;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;

public class ShopConfigListener implements PathChildrenCacheListener {


    private ZkClient zkClient;

    public ShopConfigListener(ZkClient zkClient) {
        this.zkClient = zkClient;
    }

    public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
        switch(event.getType().ordinal()) {
            case 0:
                this.registerShopConfig(event);
                break;
            case 1:
                this.registerShopConfig(event);
                break;
            case 2:
                this.removeShopConfig(event);
                break;
            case 3:
                //this.removeRouting(event);
                break;
            default:
                break;
        }

    }

    private void registerShopConfig(PathChildrenCacheEvent event) throws Exception {
        String path = event.getData().getPath();
        String config = zkClient.readWithPath(new String[]{path});
        ShopConfigDomain shopConfigDomain = JSON.parseObject(config,ShopConfigDomain.class);
        synchronized(ShopConfigService.class) {
            ShopConfigService.shopConfig.put(zkClient.getShopID(path),shopConfigDomain);
        }
    }

    private void removeShopConfig(PathChildrenCacheEvent event) throws Exception {
        String path = event.getData().getPath();
        ShopConfigService.shopConfig.remove(zkClient.getShopID(path));
    }

}

zkclient 类:zk

import com.alibaba.fastjson.JSON;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.retry.RetryUntilElapsed;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import java.util.List;

@Configuration
public class ZkClient {
    private static final Logger log = LoggerFactory.getLogger(ZkClient.class);

    @Autowired
    public ZookeeperProperties zookeeperProperties;

    private CuratorFramework curator;



    private CuratorFramework newCurator(String zkServers) throws Exception {
        CuratorFramework client = CuratorFrameworkFactory.builder()
                .connectString(zkServers)
                .retryPolicy(new RetryUntilElapsed(2147483647, 60000))
                .connectionTimeoutMs(100000)
                .sessionTimeoutMs(100000)
                .build();
        client.start();
        return client;
    }

	
	
    @PostConstruct
    public void initCuratorClient() throws Exception {
        if (!this.zookeeperProperties.validateProperties()) {
            throw new IllegalStateException("Properties config error!");
        } else {
            String zkServers = this.zookeeperProperties.getZkServer();
            if (this.curator == null) {
                this.curator = this.newCurator(zkServers);
            }
        }

        String shopConfigPath = zookeeperProperties.getShopConfigPath()+"/"+this.zookeeperProperties.getAppName();
        ShopConfigService.shopConfigPath = shopConfigPath;
        if (checkExists(shopConfigPath)) {
            List<String> childPath = getChildren(shopConfigPath);
            if(null != childPath && childPath.size()>0){
                for (String nodeName:childPath){
                    String chindNodePaht = shopConfigPath+"/"+nodeName;
                    putConfig(chindNodePaht);
                }
            }
        }else{
            write(shopConfigPath,"shopConfig");
        }
        registerShopConfigListenter(shopConfigPath);
    }

    public void putConfig(String childPath) throws Exception{
        String config = readWithPath(new String[]{childPath});
        ShopConfigDomain shopConfigDomain = JSON.parseObject(config,ShopConfigDomain.class);
        synchronized(ZkClient.class) {
            ShopConfigService.shopConfig.put(getShopID(childPath),shopConfigDomain);
        }
    }

    public Integer getShopID(String path) {
        String[] split = path.split("/");
        if(split.length >= 5) {
            return Integer.parseInt(split[5]);
        } else {
            throw new IllegalStateException("shopID is empty!");
        }
    }




    public void setData(String path, String content)throws Exception {
        this.curator.setData().forPath(path, content.getBytes("utf-8"));
    }

    public void set(String path, String content) throws Exception {
        try {
            if (this.curator.checkExists().forPath(path) == null) {
                this.curator.create()
                        .creatingParentsIfNeeded()
                        .forPath(path, content.getBytes("utf-8"));
            }
        }catch (Exception e){
            e.printStackTrace();
            throw e;
        }
    }


    public boolean checkExists(String path) throws Exception{
        if (this.curator.checkExists().forPath(path) == null) {
            return false;
        }
        return true;
    }


    public String read(String path) throws Exception {

        if (this.curator.checkExists().forPath(path) == null) {
            throw new IllegalArgumentException("Path content is empty, error!");
        } else {
            byte[] b = (byte[]) this.curator.getData().forPath(path);
            String value = new String(b, "utf-8");
            return value;
        }

    }

    /**
     * 获取子目录
     */
    public List<String> getChildren(String path) throws Exception {
        if (this.curator.checkExists().forPath(path) == null) {
            return null;
        } else {
            List children = (List) this.curator.getChildren().forPath(path);
            return children;
        }
    }

    public void registerShopConfigListenter(String path) throws Exception {
        PathChildrenCache childrenCache = new PathChildrenCache(this.curator, path, false);
        ShopConfigListener shopConfigListener = new ShopConfigListener(this);
        childrenCache.getListenable().addListener(shopConfigListener);
        childrenCache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE);

    }
    public String readWithPath(String... paths) throws Exception {
        if(paths.length == 0) {
            return null;
        } else {
            String path = null;
            String[] var3 = paths;
            int var4 = paths.length;

            for(int var5 = 0; var5 < var4; ++var5) {
                String temp = var3[var5];
                if(path == null) {
                    path = "/" + temp;
                } else {
                    path = path + "/" + temp;
                }
            }

            path = path.replaceAll("//", "/");
            return this.read(path);
        }
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值