首先确定服务注册中心的结构信息:具体如下图所示
首先定义客户端注册接口,定义了一些基本方法;
package lin.remoting.framework.register;
import java.util.List;
import java.util.Map;
/**
* 消费端注册中心
*/
public interface IRegisterCenterInvoker {
/**
* 由客户端启动首次从zookeeper中首次拉去信息
*/
public void initProviderMap();
/**
* 消费端获取服务提供者信息
* @return
*/
public Map<String,List<ProviderService>> 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<String, List<ProviderService>> providerServiceMap
= new ConcurrentHashMap<String, List<ProviderService>>();
public static final Map<String, List<ProviderService>> serviceMetaDataMapConsume
= new ConcurrentHashMap<String, List<ProviderService>>();
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<String, List<ProviderService>> 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<String, List<ProviderService>> fetchOrUpdateServiceMetaData() {
final Map<String, List<ProviderService>> providerServiceMap = new ConcurrentHashMap<String, List<ProviderService>>();
List<ProviderService> 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<String> provideServices = zkClient.getChildren(providerPath);
for (String serviceName : provideServices) {
//指定服务名下的所有提供者路劲
String servicePath = ROOT_PATH + "/" + serviceName + PROVIDER_TYPE;
//所有提供者ip
List<String> 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<ProviderService>();
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<String> currentChilds) throws Exception {
if (currentChilds == null) {
currentChilds = new ArrayList<String>();
}
List<String> tmp = new ArrayList<String>();
for (String ipPort : currentChilds) {
tmp.add(ipPort.split("\\|")[0]);
}
// System.out.println("父路径"+parentPath);
//调用函数重新刷新本地服务器数据
refreshServiceMetaDataMap(tmp);
}
});
}
}
return providerServiceMap;
}
// 根据ip来判断 一个服务提供者是否失去作用
public void refreshServiceMetaDataMap(List<String> ipList) {
if (ipList == null) {
ipList = new ArrayList<String>();
}
Map<String, List<ProviderService>> currentServiceMetaDataMap = new ConcurrentHashMap<String, List<ProviderService>>();
for (Map.Entry<String, List<ProviderService>> entry : serviceMetaDataMapConsume.entrySet()) {
String serviceName = entry.getKey();
List<ProviderService> providerServices = entry.getValue();
List<ProviderService> currentProviders = currentServiceMetaDataMap.get(serviceName);
if (currentProviders == null) {
currentProviders = new ArrayList<ProviderService>();
}
//需要全部遍历,因为一台机器可能提供多个服务
for (ProviderService providerService : providerServices) {
if (ipList.contains(providerService.getIP())) {
currentProviders.add(providerService);
}
}
currentServiceMetaDataMap.put(serviceName, currentProviders);
}
//hashMap 函数此时每个对用的serviceName已经对用当前的新服务提供者列表
//服务名相同,当前currentProviders会覆盖原键对应得值
serviceMetaDataMapConsume.putAll(currentServiceMetaDataMap);
/* Set<String> keys = serviceMetaDataMapConsume.keySet();
for (String key : keys) {
List<ProviderService> 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 {
}
关于服务器端的注册中心的实现将在我的下一篇博文为大家实现