Java tutorial
/** * Copyright (C) 2015 Baifendian Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.bfd.harpc.registry; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.imps.CuratorFrameworkState; import org.apache.curator.framework.recipes.cache.ChildData; import org.apache.curator.framework.recipes.cache.PathChildrenCache; import org.apache.curator.framework.recipes.cache.PathChildrenCache.StartMode; import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent; import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener; import org.apache.curator.framework.state.ConnectionState; import org.apache.curator.framework.state.ConnectionStateListener; import org.apache.zookeeper.CreateMode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.CollectionUtils; import com.bfd.harpc.RpcException; import com.bfd.harpc.common.Constants; import com.bfd.harpc.common.ServerNode; import com.bfd.harpc.common.ServerNodeUtils; import com.bfd.harpc.loadbalance.common.DynamicHostSet; /** * zookeeper? <br> * <br> * ApacheCuratorzookeeper? <br> * ? <a href="http://www.cnblogs.com/hupengcool/p/3982301.html">Apache * CuratorZookeeperNodePath?</a> * <p> * * @author : dsfan * @date : 2015-5-12 */ public class ZkClientRegistry implements IRegistry { /** LOGGER */ private final Logger LOGGER = LoggerFactory.getLogger(getClass()); /** zookeeper? */ private final String configPath; /** {@link PathChildrenCache} */ private PathChildrenCache cachedPath; /** {@link CuratorFramework} */ private final CuratorFramework zookeeper; /** {@link DynamicHostSet} */ private final DynamicHostSet hostSet = new DynamicHostSet(); /** {@link ServerNode} */ private final ServerNode clientNode; /** ? */ private final Object lock = new Object(); /** * @param configPath * @param zookeeper * @param clientNode */ public ZkClientRegistry(String configPath, CuratorFramework zookeeper, ServerNode clientNode) { super(); this.configPath = configPath; this.zookeeper = zookeeper; this.clientNode = clientNode; } @Override public void register(String config) throws RpcException { // zk?,? if (zookeeper.getState() == CuratorFrameworkState.LATENT) { zookeeper.start(); } // zk addListener(config); buildPathClients(config); buildPathChildrenCache(true); build(); try { cachedPath.start(StartMode.POST_INITIALIZED_EVENT); } catch (Exception e) { LOGGER.error(e.getMessage(), e); } } /** * clients * <p> * * @param config * ?? * @throws RpcException * @return ? */ private boolean buildPathClients(String config) throws RpcException { if (StringUtils.isEmpty(clientNode.getExt())) { // String address = clientNode.genAddress() + ":i_"; StringBuilder pathBuilder = new StringBuilder(configPath); pathBuilder.append(Constants.ZK_SEPARATOR_DEFAULT).append(Constants.ZK_NAMESPACE_CLIENTS) .append(Constants.ZK_SEPARATOR_DEFAULT).append(address); // try { String pathName = zookeeper.create().creatingParentsIfNeeded() .withMode(CreateMode.EPHEMERAL_SEQUENTIAL) .forPath(pathBuilder.toString(), config.getBytes(Constants.UTF8)); if (StringUtils.isNotEmpty(pathName)) { clientNode.setExt(pathName.substring(pathName.indexOf(":i_") + 1)); } return true; } catch (Exception e) { String message = MessageFormat.format("Create node error in the path : {0}", pathBuilder.toString()); LOGGER.error(message, e); throw new RpcException(message, e); } } else { // ?? String address = clientNode.genAddress(); StringBuilder pathBuilder = new StringBuilder(configPath); pathBuilder.append(Constants.ZK_SEPARATOR_DEFAULT).append(Constants.ZK_NAMESPACE_CLIENTS) .append(Constants.ZK_SEPARATOR_DEFAULT).append(address); // try { // ?zk??? if (zookeeper.checkExists().forPath(pathBuilder.toString()) == null) { zookeeper.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL) .forPath(pathBuilder.toString(), config.getBytes(Constants.UTF8)); return true; } } catch (Exception e) { String message = MessageFormat.format("Create node error in the path : {0}", pathBuilder.toString()); LOGGER.error(message, e); throw new RpcException(message, e); } } return false; } /** * ?zookeeper * <p> * * @param config * ?? */ private void addListener(final String config) { zookeeper.getConnectionStateListenable().addListener(new ConnectionStateListener() { @Override public void stateChanged(CuratorFramework curatorFramework, ConnectionState connectionState) { if (connectionState == ConnectionState.LOST) { while (true) { try { if (curatorFramework.getZookeeperClient().blockUntilConnectedOrTimedOut()) { if (buildPathClients(config)) { break; } } } catch (Exception e) { LOGGER.error(e.getMessage(), e); break; } } } } }); } /** * * <p> * * @param cacheData */ private void buildPathChildrenCache(Boolean cacheData) { cachedPath = new PathChildrenCache(zookeeper, configPath + Constants.ZK_SEPARATOR_DEFAULT + Constants.ZK_NAMESPACE_SERVERS, cacheData); cachedPath.getListenable().addListener(new PathChildrenCacheListener() { @Override public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) { PathChildrenCacheEvent.Type eventType = event.getType(); switch (eventType) { case CONNECTION_SUSPENDED: case CONNECTION_LOST: LOGGER.error("Connection error,waiting..."); return; default: } // ??,rebuild,"?"?. try { cachedPath.rebuild(); rebuild(); } catch (Exception e) { LOGGER.error("CachedPath rebuild error!", e); } } }); } /** * ?? <br> * <br> * ??zookeeper?PathChildrenCache,?{@link PathChildrenCache} * <p> * * @throws RpcException */ private void build() throws RpcException { List<String> childrenList = null; String path = configPath + Constants.ZK_SEPARATOR_DEFAULT + Constants.ZK_NAMESPACE_SERVERS; try { childrenList = zookeeper.getChildren().forPath(path); } catch (Exception e) { String message = MessageFormat.format("Get children node error in the path : {0}", path); LOGGER.error(message, e); throw new RpcException(message, e); } if (CollectionUtils.isEmpty(childrenList)) { LOGGER.error("Not find a service in zookeeper!"); throw new RpcException("Not find a service in zookeeper!"); } List<ServerNode> current = new ArrayList<ServerNode>(); for (String children : childrenList) { current.addAll(ServerNodeUtils.transfer(children)); } freshContainer(current); } /** * ??? * <p> */ protected void rebuild() { List<ChildData> children = cachedPath.getCurrentData(); if (children == null || children.isEmpty()) { // ?thrift serverzookeeper // ,?,thrift clientthrift server // ??live // <code> hostSet.getLives().clear();</> LOGGER.error("Thrift server-cluster error!"); return; } List<ServerNode> current = new ArrayList<ServerNode>(); for (ChildData data : children) { String path = data.getPath(); String address = path.substring(path.lastIndexOf(Constants.ZK_SEPARATOR_DEFAULT) + 1); LOGGER.debug("Server address {}.", address); current.addAll(ServerNodeUtils.transfer(address)); } freshContainer(current); } /** * * <p> * * @param current */ private void freshContainer(List<ServerNode> current) { synchronized (lock) { hostSet.replaceWithList(current); } } @Override public DynamicHostSet findAllService() { return hostSet; } @Override public void unregister() { try { cachedPath.close(); zookeeper.close(); } catch (Exception e) { LOGGER.error(e.getMessage(), e); } } }