学习TDD(5)--实例2:基于ZooKeeper的服务器注册和探测类[实战ServerDetector]
来源:互联网 发布:java调用外部http接口 编辑:程序博客网 时间:2024/06/05 11:38
接下来我们来写发现可用服务器的工具类ServerDetector。以后不再写这种复杂实例的博客了,写了好久啊。示例代码已上传到http://download.csdn.net/detail/mrbcy/9753008
测试类
package tech.mrbcy.mrpc.test.client;import java.net.InetSocketAddress;import java.util.concurrent.CountDownLatch;import java.util.concurrent.TimeUnit;import org.junit.Assert;import org.junit.Before;import org.junit.Test;import tech.mrbcy.mrpc.client.ServerDetector;import tech.mrbcy.mrpc.server.ServerRegister;public class ServerDetectorTest { private String zkConnetionString = "amaster:2181,anode1:2181,anode2:2181"; private String groupName = "/MrpcServer"; private String serverNode = "/ServiceImplServer"; private int closeCount = 0; private CountDownLatch latch; private boolean reconnect = false; @Before public void init(){ closeCount = 0; latch = new CountDownLatch(1); reconnect = false; } @Test public void testServerChange() throws Exception{ final ServerRegister sr1 = new ServerRegister(zkConnetionString, groupName); sr1.registServer(serverNode,"localhost:8000"); final ServerRegister sr2 = new ServerRegister(zkConnetionString, groupName); sr2.registServer(serverNode,"localhost:8001"); final ServerRegister sr3 = new ServerRegister(zkConnetionString, groupName); sr3.registServer(serverNode,"localhost:8002"); ServerDetector serverDetector = new ServerDetector(zkConnetionString,groupName); InetSocketAddress serverAddr = serverDetector.getAServer(new ServerSwitchListener() { public void serverSwitched(InetSocketAddress newServerAddr) { if(newServerAddr == null){ latch.countDown(); }else{ try { closeServer(sr1,sr2,sr3,newServerAddr); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }); Assert.assertNotNull(serverAddr); closeServer(sr1,sr2,sr3,serverAddr); latch.await(); Assert.assertEquals(closeCount, 3); } @Test(expected = RuntimeException.class) public void testUnAvailableZk() throws Exception{ new ServerDetector("anode3:2181",groupName); } @Test public void testNoListener() throws Exception{ final ServerRegister sr1 = new ServerRegister(zkConnetionString, groupName); sr1.registServer(serverNode,"localhost:8000"); final ServerRegister sr2 = new ServerRegister(zkConnetionString, groupName); sr2.registServer(serverNode,"localhost:8001"); final ServerRegister sr3 = new ServerRegister(zkConnetionString, groupName); sr3.registServer(serverNode,"localhost:8002"); ServerDetector serverDetector = new ServerDetector(zkConnetionString,groupName); InetSocketAddress serverAddr = serverDetector.getAServer(null); System.out.println("获得服务器地址:" + serverAddr.getHostString() + ":" + serverAddr.getPort()); } @Test public void testNoServer() throws Exception{ ServerDetector serverDetector = new ServerDetector(zkConnetionString,groupName); InetSocketAddress serverAddr = serverDetector.getAServer(null); Assert.assertNull(serverAddr); } @Test(expected = RuntimeException.class) public void testEmptyNodeString() throws Exception{ new ServerDetector(zkConnetionString,""); } @Test(expected = RuntimeException.class) public void testObliqueNodeString() throws Exception{ new ServerDetector(zkConnetionString,""); } @Test public void testNodePathNotStartWithOblique() throws Exception{ final ServerRegister sr1 = new ServerRegister(zkConnetionString, groupName); sr1.registServer(serverNode,"localhost:8000"); final ServerRegister sr2 = new ServerRegister(zkConnetionString, groupName); sr2.registServer(serverNode,"localhost:8001"); final ServerRegister sr3 = new ServerRegister(zkConnetionString, groupName); sr3.registServer(serverNode,"localhost:8002"); ServerDetector serverDetector = new ServerDetector(zkConnetionString,"MrpcServer"); InetSocketAddress serverAddr = serverDetector.getAServer(null); System.out.println("获得服务器地址:" + serverAddr.getHostString() + ":" + serverAddr.getPort()); } @Test public void testReconnect() throws Exception { final ServerRegister sr1 = new ServerRegister(zkConnetionString, groupName); sr1.registServer(serverNode,"localhost:8000"); final ServerRegister sr2 = new ServerRegister(zkConnetionString, groupName); sr2.registServer(serverNode,"localhost:8001"); final ServerRegister sr3 = new ServerRegister(zkConnetionString, groupName); sr3.registServer(serverNode,"localhost:8002"); ServerDetector serverDetector = new ServerDetector(zkConnetionString,"MrpcServer"); InetSocketAddress serverAddr = serverDetector.getAServer(new ServerSwitchListener() { public void serverSwitched(InetSocketAddress newServerAddr) { System.out.println("获得服务器地址:" + newServerAddr.getHostString() + ":" + newServerAddr.getPort()); reconnect = true; latch.countDown(); } }); System.out.println("获得服务器地址:" + serverAddr.getHostString() + ":" + serverAddr.getPort()); // 手动重启zk集群 latch.await(200, TimeUnit.SECONDS); closeServer(sr1, sr2, sr3, serverAddr); Thread.sleep(10000); Assert.assertTrue(reconnect); } private void closeServer(ServerRegister sr1, ServerRegister sr2, ServerRegister sr3, InetSocketAddress serverAddr) throws Exception { closeCount += 1; if(serverAddr.getPort() == 8000){ sr1.unregist(); }else if(serverAddr.getPort() == 8001){ sr2.unregist(); }else if(serverAddr.getPort() == 8002){ sr3.unregist(); } }}
根据测试类,写出的ServerDetector
package tech.mrbcy.mrpc.client;import java.io.IOException;import java.net.InetSocketAddress;import java.util.ArrayList;import java.util.List;import java.util.Random;import java.util.concurrent.CountDownLatch;import java.util.concurrent.TimeUnit;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.ZooKeeper;import org.apache.zookeeper.Watcher.Event.EventType;import tech.mrbcy.mrpc.test.client.ServerSwitchListener;public class ServerDetector implements Watcher { private String zkConnetionString; private String nodePath; private int sessionTimeout = 2000; private ZooKeeper zk; private ServerSwitchListener serverSwitchListener; private InetSocketAddress curServer; private CountDownLatch latch; /** * 使用连接zk集群的字符串和节点路径创建探测器类 * @param zkConnetionString zk集群的连接字符串 * @param nodePath 节点路径 * @throws Exception 连接到zk集群过程中出错将抛出异常 */ public ServerDetector(String zkConnetionString, String nodePath) throws Exception { this.zkConnetionString = zkConnetionString; if(nodePath.equals("") || nodePath.equals("/")){ throw new RuntimeException("nodePath can't be empty"); } if(!nodePath.startsWith("/")){ nodePath = "/" + nodePath; } this.nodePath = nodePath; initZk(); } // 初始化zk客户端 private void initZk() throws Exception { latch = new CountDownLatch(1); this.zk = new ZooKeeper(zkConnetionString, sessionTimeout, this); latch.await(sessionTimeout, TimeUnit.MILLISECONDS); if(latch.getCount() > 0){ throw new RuntimeException("Can not connect to ZooKeeper cluster " + zkConnetionString + ", please check and try again later"); } // 注册监听 getServerList(); } // 刷新服务器列表 private InetSocketAddress refreshServerList() throws Exception { // 获取服务器列表 List<String> serversList = getServerList(); boolean isCurServerAvailable = checkServerList(serversList); if(!isCurServerAvailable){ this.curServer = chooseAServer(serversList); if(this.serverSwitchListener != null){ serverSwitchListener.serverSwitched(this.curServer); } } return curServer; } private InetSocketAddress chooseAServer(List<String> servers) { if(servers == null || servers.size() == 0){ return null; } // 随机选择一个服务器 String serverAddr = servers.get(0); if(servers.size() > 1){ int index = new Random().nextInt(servers.size()); serverAddr = servers.get(index); } String[] addrAndPort = serverAddr.split(":"); if(addrAndPort.length != 2){ throw new RuntimeException("不合法的server地址:" + serverAddr); } return new InetSocketAddress(addrAndPort[0], Integer.parseInt(addrAndPort[1])); } private boolean checkServerList(List<String> servers) { if(servers == null || servers.size() == 0){ return false; } // 未指定服务器地址或原服务器已失效,迁移到新的服务器 if(servers.size() > 0 && curServer != null){ for(String server:servers){ if(server.equals(curServer.getHostString() + ":" + curServer.getPort())){ return true; } } } return false; } private List<String> getServerList() throws Exception { List<String> serverNodes = zk.getChildren(nodePath, true); List<String> serverAddrs = new ArrayList<String>(); for(String serverNode : serverNodes){ serverAddrs.add(new String(zk.getData(nodePath+"/" + serverNode, null, null))); } return serverAddrs; } /** * 获取一个可用的服务器连接地址 * @param serverSwitchListener 如果之前返回的服务器连接地址失效,将回调通知 * @return 没有可用的服务器时返回null * @throws Exception */ public InetSocketAddress getAServer( ServerSwitchListener serverSwitchListener) throws Exception { this.serverSwitchListener = null; InetSocketAddress newAddress = refreshServerList(); this.serverSwitchListener = serverSwitchListener; return newAddress; } public void process(WatchedEvent event) { System.out.println("detector:------" + event); if(event.getState() == Event.KeeperState.SyncConnected){ latch.countDown(); } if(event.getState() == Event.KeeperState.Expired){ try { // 会话过期,重新连接ZooKeeper集群 initZk(); } catch (Exception e1) { e1.printStackTrace(); } } if(event.getType() == EventType.NodeChildrenChanged){ try { refreshServerList(); } catch (Exception e) { e.printStackTrace(); } } }}
0 0
- 学习TDD(5)--实例2:基于ZooKeeper的服务器注册和探测类[实战ServerDetector]
- 学习TDD(4)--实例2:基于ZooKeeper的服务器注册和探测类[实战ServerRegister]
- 学习TDD(3)--实例2:基于ZooKeeper的服务器注册和探测类[分析篇]
- 学习TDD(2)--实例:ProtoStuffUtil类的测试
- 基于机器学习的TDD开发模式
- 基于Zookeeper服务注册和发现
- 学习TDD(1)--TDD的步骤和好处
- 基于YARA 和NESSUS 的威胁探测
- 学习TDD:TDD的好处
- 学习TDD:TDD的好处
- 基于ZooKeeper的Dubbo注册中心
- 基于ZooKeeper的Dubbo注册中心
- 基于ZooKeeper的Dubbo注册中心
- 基于ZooKeeper的Dubbo注册中心
- 基于Zookeeper的服务注册与发现
- 基于ZooKeeper的Dubbo注册中心
- 基于ZooKeeper的服务注册中心
- 基于Zookeeper的服务注册与发现
- 线性代数-【2-1】矩阵及其运算
- C++学习一静态成员与静态成员函数
- 01-iOS蓝牙开发简介
- 02-iOS蓝牙连接流程介绍
- iOS开发之block解析
- 学习TDD(5)--实例2:基于ZooKeeper的服务器注册和探测类[实战ServerDetector]
- 03-iOS蓝牙架构搭建
- android远程服务
- [10]项目实战-PC 端固定布局(10)
- 51871791
- 04-iOS蓝牙传输数据演示
- 05-iOS蓝牙开发总结
- hadoop编程工具类
- HDU 3966 Aragorn's Story (树链剖分)