上一篇文章《手把手教你写rpc框架系列(五)定义zookeeper数据交互的序列化和反序列化》我们介绍了zookeeper元数据的序列化和反序列化,这篇文章我们就来实现整个微服务的自动注册。
首先我们定义一个register的注册接口,里面主要做两件事情,第一件事向zookeeper注册服务,第二件事是从zookeeper获取注册的服务,定义的接口类是:ServiceRegister,完整代码如下:
package org.wz.rpc.framework.register;
import org.wz.rpc.framework.model.ServiceObject;
public interface ServiceRegister {
//需要把服务注册到注册中心去
void register(ServiceObject serviceObject) throws Exception;
//需要把服务从注册中心给查出来
ServiceObject getServiceObject(String serviceName) throws Exception;
}既然有了注册的业务接口,那么我们肯定是需要编写一个实现类的,这里我们先编写一个本地缓存的简单实现类,主要是把注册的信息存放在map里面,然后获取服务的时候,直接从这个map里面获取即可,实现类是:DefaultServiceRegister,完整代码如下:
package org.wz.rpc.framework.register;
import java.util.HashMap;
import java.util.Map;
import org.wz.rpc.framework.model.ServiceObject;
/**
* 默认服务注册器
*/
public class DefaultServiceRegister implements ServiceRegister {
/**
* 把service缓存在内存中,这样子方便直接进行读写
*/
private Map<String, ServiceObject> serviceMap = new HashMap<String, ServiceObject>();
@Override
public void register(ServiceObject serviceObject) throws Exception {
if (serviceObject == null) {
throw new RuntimeException("注册的服务信息为空,请检查");
}
this.serviceMap.put(serviceObject.getName(), serviceObject);
}
@Override
public ServiceObject getServiceObject(String serviceName) {
return this.serviceMap.get(serviceName);
}
}上面这个类其实相当于是一个本地缓存的服务,在真实的情况下,一般我们向zookeeper注册的时候,会在本地存储一份,上面我们编写了本地存储的那份,但是还没有编写向zookeeper注册的逻辑,所以这里我们编写一个ZookeeperServiceRegister类,实现向zookeeper注册。ZookeeperServiceRegister类的完整代码如下:
package org.wz.rpc.framework.register;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.URLEncoder;
import org.I0Itec.zkclient.ZkClient;
import org.wz.rpc.framework.model.ServiceObject;
import org.wz.rpc.framework.model.ZookeeperMetadataData;
import org.wz.rpc.framework.serializer.ZookeeperSerializer;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ZookeeperServiceRegister extends DefaultServiceRegister implements ServiceRegister {
// 定义ZkClient
private ZkClient client;
// 定义元数据的协议
private String protocol;
// 定义服务暴露的端口
private Integer port;
/**
* 初始化的时候,把zookeeper的信息初始化进去
*
* @param zkAddress
* @param port
* @param protocol
*/
public ZookeeperServiceRegister(String zkAddress, Integer port, String protocol) {
log.info("初始化zookeeper连接");
client = new ZkClient(zkAddress);
client.setZkSerializer(new ZookeeperSerializer());
this.port = port;
this.protocol = protocol;
}
@Override
public void register(ServiceObject serviceObject) throws Exception {
log.info("准备向zookeeper注册自身服务信息:{}", JSON.toJSONString(serviceObject));
super.register(serviceObject);
// 首先拼接存储到zookeeper上的元数据信息
ZookeeperMetadataData metaData = this.getNewZookeeperMetaData(serviceObject);
this.writeMetaData2Zookeeper(metaData);
}
private void writeMetaData2Zookeeper(ZookeeperMetadataData meta) {
// servicename,例如:org.shop.api.UserService
String serviceName = meta.getName();
String uri = JSON.toJSONString(meta);
try {
// 例如:
// {"address":"192.168.31.147:18000","name":"org.shop.api.UserService","protocol":"wz-rpc"}
uri = URLEncoder.encode(uri, RPCConstants.UTF_8);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// zookeeper写数据的路径,例如:/wz-rpc/org.shop.api.UserService/service
String servicePath = RPCConstants.ZK_SERVICE_PATH + RPCConstants.PATH_DELIMITER + serviceName + "/service";
if (!client.exists(servicePath)) {
client.createPersistent(servicePath, true);
}
// 这里是把数据写入到路径里面去
String uriPath = servicePath + RPCConstants.PATH_DELIMITER + uri;
if (client.exists(uriPath)) {
client.delete(uriPath);
}
client.createEphemeral(uriPath);
}
/**
* 构建新的实例的元数据信息
*
* @param serviceObject
* @return
* @throws Exception
*/
private ZookeeperMetadataData getNewZookeeperMetaData(ServiceObject serviceObject) throws Exception {
ZookeeperMetadataData meta = new ZookeeperMetadataData();
String host = InetAddress.getLocalHost().getHostAddress();
String address = host + ":" + port;
meta.setAddress(address);
meta.setName(serviceObject.getClazz().getName());
meta.setProtocol(protocol);
return meta;
}
}这里的逻辑就是调用zookeeper的api,实现向zookeeper进行注册,同时这里的
super.register(serviceObject);
实现了把注册信息填写到本地的内存中。
以上我们编写的zookeeper注册客户端的工具类就实现了,按照惯例,附上本案例的源码,登录后即可下载。









还没有评论,来说两句吧...