package com.easyooo.framework.support.zookeeper; import static org.springframework.util.Assert.notNull; import org.apache.curator.RetryPolicy; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.framework.imps.CuratorFrameworkState; import org.apache.curator.retry.ExponentialBackoffRetry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; /** * Zookeeper client factory bean,它是单实例的, * 意味着程序只有一个zk client的实例 * * <p> * 支持VM参数配置zk连接字符串如:-DzkConnectionString=192.168.1.1:2181 * 或者SPring配置文件注入的方式 * </p> * * @author Killer */ public class ZookeeperClientFactoryBean implements FactoryBean<CuratorFramework>, InitializingBean, DisposableBean { private Logger logger = LoggerFactory.getLogger(getClass()); // 默认15毫秒连接超时时间 private static final Integer DEFAULT_CONNECTION_TIMEOUT = 15 * 1000; // session有效期60ms private static final Integer DEFAULT_SESSION_TIMEOUT = 60 * 1000; private CuratorFramework zkClient; /** * Zookeeper 连接字符串, 这是需要注入的! */ private String connectionString; private Integer connectionTimeout = DEFAULT_CONNECTION_TIMEOUT; private Integer sessionTimeout = DEFAULT_SESSION_TIMEOUT; private Integer maxRetries = 5; private int baseSleepTimeMs = 1000; @Override public void afterPropertiesSet() { // 优先系统参数中的ZK配置,如果VM启动参数中没有该参数,则取Spring注入的属性 connectionString = System.getProperty("zkConnectionString", connectionString); notNull(connectionString, "Property 'connectionString' is required"); this.zkClient = createZookeeperInstance(); this.zkClient.start(); if(this.zkClient.getState() == CuratorFrameworkState.STARTED){ logger.info("ZK connection is successful."); }else{ logger.error("ZK connection is unsuccessful."); } } @Override public CuratorFramework getObject() { return zkClient; } @Override public Class<?> getObjectType() { return CuratorFramework.class; } @Override public boolean isSingleton() { return true; } @Override public void destroy() throws Exception { if(zkClient != null && zkClient.getState() != CuratorFrameworkState.STOPPED){ zkClient.close(); } } public CuratorFramework createZookeeperInstance() { // 重试策略 RetryPolicy rp = new ExponentialBackoffRetry(baseSleepTimeMs, maxRetries); // create ZK Client CuratorFramework cf = CuratorFrameworkFactory.builder() .connectString(connectionString) .retryPolicy(rp) .connectionTimeoutMs(connectionTimeout) .sessionTimeoutMs(sessionTimeout) .build(); return registListener(cf); } /** * 注册Zookeeper客户端连接状态及异常的日志监听器 * * @param client * @return */ private CuratorFramework registListener(CuratorFramework client) { LogConnectionStateListener lc = new LogConnectionStateListener(); client.getConnectionStateListenable().addListener(lc); client.getUnhandledErrorListenable().addListener(lc); return client; } public void setZkClient(CuratorFramework zkClient) { this.zkClient = zkClient; } public void setConnectionString(String connectionString) { this.connectionString = connectionString; } public void setConnectionTimeout(Integer connectionTimeout) { this.connectionTimeout = connectionTimeout; } public void setSessionTimeout(Integer sessionTimeout) { this.sessionTimeout = sessionTimeout; } public void setMaxRetries(Integer maxRetries) { this.maxRetries = maxRetries; } public void setBaseSleepTimeMs(int baseSleepTimeMs) { this.baseSleepTimeMs = baseSleepTimeMs; } }