首先确定服务注册中心的结构信息:具体如下图所示
首先定义客户端注册接口,定义了一些基本方法;
package lin.remoting.framework.register; import java.util.List; import java.util.Map; /** * 消费端注册中心 */ public interface IRegisterCenterInvoker { /** * 由客户端启动首次从zookeeper中首次拉去信息 */ public void initProviderMap(); /** * 消费端获取服务提供者信息 * @return */ public Map> getServiceMetaDataMap4Consume(); public void registerInvoker(final InvokerService invoker); }
具体实现类如下:
package lin.remoting.framework.register; import org.I0Itec.zkclient.IZkChildListener; import org.I0Itec.zkclient.ZkClient; import org.I0Itec.zkclient.serialize.SerializableSerializer; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** * 服务调用者注册中心 */ public class RegisterCenterInvoker implements IRegisterCenterInvoker { //服务提供者列表:key :服务提供者接口,value:服务提供者服务方法列表 private static final Map> providerServiceMap = new ConcurrentHashMap >(); public static final Map > serviceMetaDataMapConsume = new ConcurrentHashMap >(); private static volatile ZkClient zkClient = null; private static String ZK_SERVICE = "127.0.0.1"; private static int ZK_SESSION_TIME_OUT = 999999; private static int ZK_CONNECTION_TIME_OUT = 999999; private static RegisterCenterInvoker RegisterCenterInvoker = new RegisterCenterInvoker(); private static String ROOT_PATH = "/config_register/" + "lin"; private static String PROVIDER_TYPE = "/provider"; private static String INVOKER_TYPE = "/consumer"; private RegisterCenterInvoker() { } public static RegisterCenterInvoker singleton() { return RegisterCenterInvoker; } public void initProviderMap() { if (serviceMetaDataMapConsume.isEmpty()) { serviceMetaDataMapConsume.putAll(fetchOrUpdateServiceMetaData()); } } /** * 使用该函数前请确保已经使用initProviderMap()已近从zookeeper拉取消息到本地进行缓存 * * @return */ public Map > getServiceMetaDataMap4Consume() { return serviceMetaDataMapConsume; } /** * 该函数用于消费者将自身信息注册到zookeeper上 * * @param invoker */ public void registerInvoker(InvokerService invoker) { if (invoker == null) { return; } synchronized (RegisterCenterInvoker.class) { if (zkClient == null) { zkClient = new ZkClient(ZK_SERVICE, ZK_SESSION_TIME_OUT, ZK_CONNECTION_TIME_OUT, new SerializableSerializer()); } boolean exist = zkClient.exists(ROOT_PATH); if (!exist) { zkClient.createPersistent(ROOT_PATH, true); } //创建服务消费者节点 String consumeName = invoker.getTargetInterface().getSimpleName(); exist = zkClient.exists(ROOT_PATH+"/"+consumeName); if (!exist) { zkClient.createPersistent(ROOT_PATH+"/"+consumeName); } String consumeNodePath = ROOT_PATH + "/" + consumeName + INVOKER_TYPE; exist = zkClient.exists(consumeNodePath); if (!exist) { zkClient.createPersistent(consumeNodePath); } //创建当前服务端节点 String localIp = invoker.getIP(); String currentConsumeServicePath = consumeNodePath + "/" + localIp; exist = zkClient.exists(currentConsumeServicePath); if (!exist) { zkClient.createEphemeral(currentConsumeServicePath); } } } private Map > fetchOrUpdateServiceMetaData() { final Map > providerServiceMap = new ConcurrentHashMap >(); List providerServices = null; //连接zk 加锁防止重复注册。 synchronized (IRegisterCenterInvoker.class) { if (zkClient == null) { zkClient = new ZkClient(ZK_SERVICE, ZK_SESSION_TIME_OUT, ZK_CONNECTION_TIME_OUT, new SerializableSerializer()); } //从这里开始从服务器获取服务提供者列表 String providerPath = ROOT_PATH; //获取根节点下所有的子节点 List provideServices = zkClient.getChildren(providerPath); for (String serviceName : provideServices) { //指定服务名下的所有提供者路劲 String servicePath = ROOT_PATH + "/" + serviceName + PROVIDER_TYPE; //所有提供者ip List ipPathList = zkClient.getChildren(servicePath); for (String ipPath : ipPathList) { String[] ipAndPort = ipPath.split("\\|"); String serverIp = ipAndPort[0]; String serverPort = ipAndPort[1]; //引用型 与初始创的为同一个引用 providerServices = providerServiceMap.get(serviceName); if (providerServices == null) { providerServices = new ArrayList (); providerServiceMap.put(serviceName, providerServices); } ProviderService providerService = new ProviderService(); try { //将服务名转化为类 这里根据自己的实际情况设置,事实上这里可以通过配置 //文件来确定 providerService.setTargetInterface(Class.forName("lin.remoting.framework.register." + serviceName)); } catch (Exception e) { throw new RuntimeException(e); } providerService.setIP(serverIp); providerService.setPort(Integer.parseInt(serverPort)); //将服务添加到列表当中 providerServices.add(providerService); } //遍历完后将服务列表添加到其中 providerServiceMap.put(serviceName, providerServices); zkClient.subscribeChildChanges(servicePath, new IZkChildListener() { public void handleChildChange(String parentPath, List currentChilds) throws Exception { if (currentChilds == null) { currentChilds = new ArrayList (); } List tmp = new ArrayList (); for (String ipPort : currentChilds) { tmp.add(ipPort.split("\\|")[0]); } // System.out.println("父路径"+parentPath); //调用函数重新刷新本地服务器数据 refreshServiceMetaDataMap(tmp); } }); } } return providerServiceMap; } // 根据ip来判断 一个服务提供者是否失去作用 public void refreshServiceMetaDataMap(List ipList) { if (ipList == null) { ipList = new ArrayList (); } Map > currentServiceMetaDataMap = new ConcurrentHashMap >(); for (Map.Entry > entry : serviceMetaDataMapConsume.entrySet()) { String serviceName = entry.getKey(); List providerServices = entry.getValue(); List currentProviders = currentServiceMetaDataMap.get(serviceName); if (currentProviders == null) { currentProviders = new ArrayList (); } //需要全部遍历,因为一台机器可能提供多个服务 for (ProviderService providerService : providerServices) { if (ipList.contains(providerService.getIP())) { currentProviders.add(providerService); } } currentServiceMetaDataMap.put(serviceName, currentProviders); } //hashMap 函数此时每个对用的serviceName已经对用当前的新服务提供者列表 //服务名相同,当前currentProviders会覆盖原键对应得值 serviceMetaDataMapConsume.putAll(currentServiceMetaDataMap); /* Set keys = serviceMetaDataMapConsume.keySet(); for (String key : keys) { List providerServices = RegisterCenterInvoker.serviceMetaDataMapConsume.get(key); // System.out.println("跟新大小" + providerServices.size() + "size"); for (ProviderService providerService : providerServices) { System.out.println(providerService); } } */ } }
下面是上面所用到的一些类
package lin.remoting.framework.register; /** * 用于封装一个服务消费者的基本信息 */ public class InvokerService { private Class> targetInterface; private String IP; public InvokerService(Class> targetInterface, String IP) { this.targetInterface = targetInterface; this.IP = IP; } public Class> getTargetInterface() { return targetInterface; } public void setTargetInterface(Class> targetInterface) { this.targetInterface = targetInterface; } public String getIP() { return IP; } public void setIP(String IP) { this.IP = IP; } }
package lin.remoting.framework.register; //该类用于封装提供服务类消息 public class ProviderService { //服务接口 即该服务提供者面向的对象 private Class> targetInterface; //服务提供者地址 private String IP; //服务提供者的端口号; private int port; public Class> getTargetInterface() { return targetInterface; } public void setTargetInterface(Class> targetInterface) { this.targetInterface = targetInterface; } public String getIP() { return IP; } public void setIP(String IP) { this.IP = IP; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } @Override public String toString() { return this.targetInterface.getName() + " IP: " + this.IP + " port: " + this.port; } }
package lin.remoting.framework.register; public class Myservice { }
关于服务器端的注册中心的实现将在我的下一篇博文为大家实现