基于zookeeper实现分布式配置中心(二)

  

       上一篇(基于zookeeper实现分布式配置中心(一))讲述了zookeeper相关概念和工作原理。接下来根据zookeeper的特性,简单实现一个分布式配置中心。

配置中心的优势

1、各环境配置集中管理。

2、配置更改,实时推送,jvm环境变量及时生效。

3、依靠配置变更,动态扩展功能,减少二次上线带来的成本。

4、减少开发人员、运维人员修改配置带来的额外开销。

 配置中心架构图

  

配置中心功能

1、配置管理平台中,操作人员可以创建项目所属系统、应用名称、实例名称、配置分组等信息。

2、配置管理平台中,操作人员可以上传配置文件,对属性有增、删、改、查的操作。

3、配置内容通过配置管理平台后台服务进行持久化(保存到数据库中)。

4、操作人员通过配置平台进行推送操作,将配置推送到zk集群相应结点(/cfgcenter/系统名称/应用名称/实例名称/分组名称)。

5、配置中心客户端监听zk集群中对应结点数据发生变化,读取变更后的内容,解析内容,刷新本地备份(分布式容灾)和Spring环境变量。

6、配置中心客户端如果和zk集群丢失连接,将加载本地本分配置到Spring环境变量。

7、配置中心客户端重新和zk集群建立连接,从zk集群中拉取最新配置内容,解析配置,刷新本地备份(分布式容灾)和Spring环境变量。

8、配置中心客户端将Spring环境变量刷新之后,动态刷新依赖配置中心配置的bean。

配置中心代码视图  

  

配置中心客户端设计解析

配置中心客户端初始化

@Component
public class CfgcenterInit implements ApplicationContextInitializer<ConfigurableWebApplicationContext>, ApplicationListener<ApplicationEvent> {

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

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ContextRefreshedEvent) {
            LOGGER.info("初始化配置中心客户端监听器...");
            ZKClient.getInstance()
                    .init();
        } else if (event instanceof RefreshEvent) {
            ZKClient.getInstance()
                    .getAeb()
                    .post(event);
        } else if (event instanceof ContextClosedEvent) {
            if (null != ZKClient.getInstance().getCw()) {
                ZKClient.getInstance()
                        .getCw()
                        .close();
            }
        }
    }

    @Override
    public void initialize(ConfigurableWebApplicationContext cac) {
        try {
            ZookeeperProperties zookeeperProperties = ConfigurationBinder
                    .withPropertySources(cac.getEnvironment())
                    .bind(ZookeeperProperties.class);
            if (!zookeeperProperties.isEnabled()) {
                LOGGER.info("未开启配置中心客戶端...");
                return;
            }
            ZKClient.getInstance()
                    .binding(
                            zookeeperProperties
                            , new ZookeeperConfigProperties()
                            , cac
                    );
        } catch (Exception e) {
            LOGGER.error("配置中心客户端初始化异常...", e);
        }
    }
}

1、ApplicationContextInitializer#initialize方法中,获取zk连接信息配置,如果开启配置中心客户端,将ZookeeperProperties(zk集群连接信息)、ZookeeperConfigProperties(客户端监听zk集群结点信息)、ConfigurableWebApplicationContext (应用上下文)绑定到ZKClient实例中去。

2、ApplicationListener#onApplicationEvent方法中监听ContextRefreshedEvent(初始化配置中心客户端监听器)、RefreshEvent(配置刷新事件,通过guava的事件总线进行推送)、ContextClosedEvent(关闭配置中心客户端资源)。

配置中心客户端监听器

public class ConfigWatcher implements Closeable, TreeCacheListener {

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

    private AtomicBoolean running = new AtomicBoolean(false);
    private String context;
    private CuratorFramework source;
    private HashMap<String, TreeCache> caches;

    public ConfigWatcher(String context, CuratorFramework source) {
        this.context = context;
        this.source = source;
    }

    public void start() {
        if (this.running.compareAndSet(false, true)) {
            this.caches = new HashMap<>();
            if (!context.startsWith("/")) {
                context = "/" + context;
            }
            try {
                TreeCache cache = TreeCache.newBuilder(this.source, context).build();
                cache.getListenable().addListener(this);
                cache.start();
                this.caches.put(context, cache);
                // no race condition since ZookeeperAutoConfiguration.curatorFramework
                // calls curator.blockUntilConnected
            } catch (KeeperException.NoNodeException e) {
                // no node, ignore
            } catch (Exception e) {
                LOGGER.error("Error initializing listener for context " + context, e);
            }
        }
    }

    @Override
    public void close() {
        if (this.running.compareAndSet(true, false)) {
            for (TreeCache cache : this.caches.values()) {
                cache.close();
            }
            this.caches = null;
        }
    }

    @Override
    public void childEvent(CuratorFramework client, TreeCacheEvent event) {
        TreeCacheEvent.Type eventType = event.getType();
        switch (eventType) {
            case INITIALIZED:
                LOGGER.info("配置中心客户端同步服务端状态完成...");
                refreshEnvAndBeans(event);
                break;
            case NODE_REMOVED:
            case NODE_UPDATED:
                refreshEnvAndBeans(event);
                break;
            case CONNECTION_SUSPENDED:
            case CONNECTION_LOST:
                LOGGER.info("配置中心客户端与服务端连接异常...");
                break;
            case CONNECTION_RECONNECTED:
                LOGGER.in
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值