该篇主要完成,资源节点添加、删除、获取资源节点地址列表。
1、设计目的
注册中心存储资源节点信息,以便向发送端提供服务地址列表。
2、主要功能
- 资源拥有者,向注册中心注册资源。
- 发送端向注册中心报告健康值状况。
- 注册中心,向接收端提供服务地址列表。
3、资源拥有者池
- 服务地址列表
private static final Map<Integer, List<Node>> ownerPool;
key:资源id
value:服务地址列表。
- 接收端注册
private static final Map<Integer, ResourceNodeInfo> nodePool;
key : 资源网络节点hashcode;
value:资源节点信息。
- 资源节点信息ResourceNodeInfo
package man.kuke.registry;
/**
* @author: kuke
* @date: 2020/12/5 - 21:57
* @description:
*/
public class ResourceNodeInfo {
private Node node;
//用于记录资源网络节点地址及注册的资源个数。
private int resourceCount;
public ResourceNodeInfo(Node node) {
this.resourceCount = 0;
this.node = node;
}
public ResourceNodeInfo() {
}
public Node getNode() {
return node;
}
public void setNode(Node node) {
this.node = node;
}
public int getResourceCount() {
return resourceCount;
}
public int deCount() {
return resourceCount--;
}
public int incCount() {
return resourceCount++;
}
//设置资源节点健康值
public void setHealth(int health) {
node.setHealth(health);
}
}
- 资源拥有者池
package man.kuke.registry;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author: kuke
* @date: 2020/12/5 - 19:19
* @description:
*/
public class ResourOwnerPool {
/**
* 资源拥有者
* 这里增加资源拥有者节点
* map键值对添加存在线程安全
* list 生成存在线程安全。
* list 多线程增加节点存在安全
* key = 资源id
*/
private static final Map<Integer, List<Node>> ownerPool;
/**
* 节点信息
* map键值对添加存在线程安全
* ResourceNodeInfo 生成存在线程安全
* key = (node.port + node.ip).hashcode
*/
private static final Map<Integer, ResourceNodeInfo> nodePool;
private static final Object resourceNodeInfoLock;
private static final Object listLock;
static {
ownerPool = new ConcurrentHashMap<>();
nodePool = new ConcurrentHashMap<>();
resourceNodeInfoLock = new Object();
listLock = new Object();
}
public ResourOwnerPool() {
}
private ResourceNodeInfo checkAddress(Node node) {
return nodePool.get(node.hashCode());
}
//获取发送端节点信息
private ResourceNodeInfo checkAndGetAddress(Node node) {
Integer nodeHashCode = node.hashCode();
ResourceNodeInfo orgNode = nodePool.get(nodeHashCode);
if (orgNode == null) {
synchronized (listLock) {
orgNode = nodePool.get(nodeHashCode);
//该两个操作应为原子性
if (orgNode == null) {
orgNode = new ResourceNodeInfo(node);
nodePool.put(nodeHashCode, orgNode);
}
}
}
return orgNode;
}
//注册资源
void addResource(Integer resourceId, Node node) {
ResourceNodeInfo nodeInfo = checkAndGetAddress(node);
node = nodeInfo.getNode();
List<Node> resourceNodeList = ownerPool.get(resourceId);
//resourceNodeList 和ownerPool 都已经加锁,为何还需要synchronized
//为了提高程序效率
if (resourceNodeList == null) {
synchronized (resourceNodeInfoLock) {
resourceNodeList = ownerPool.get(resourceId);
if (resourceNodeList == null) {
resourceNodeList = Collections.synchronizedList(new ArrayList<>());
ownerPool.put(resourceId, resourceNodeList);
}
}
}
resourceNodeList.add(node);
nodeInfo.incCount();
}
//注销资源
void removeResource(Node node, Integer resourceId) {
ResourceNodeInfo nodeInfo = checkAddress(node);
if (nodeInfo == null) {
return;
}
//资源拥有者列表
List<Node> resourceNodeList = ownerPool.get(resourceId);
if (resourceNodeList == null) {
return;
}
resourceNodeList.remove(nodeInfo.getNode());
if (nodeInfo.deCount() <= 0) {
nodePool.remove(nodeInfo.hashCode());
}
}
//注销发送端
void removeNode(Node node) {
ResourceNodeInfo nodeInfo = checkAddress(node);
if (nodeInfo == null) {
return;
}
Set<Integer> resourceIdSet = ownerPool.keySet();
for (Integer resourceId : resourceIdSet) {
List<Node> nodes = ownerPool.get(resourceId);
nodes.remove(node);
}
nodePool.remove(nodeInfo.hashCode());
}
//设置发送端健康值
void setNodeHealth(Node node, int health) {
ResourceNodeInfo nodeInfo = checkAddress(node);
if (nodeInfo == null) {
return;
}
nodeInfo.setHealth(health);
}
//获取地址列表
List<Node> getNodeList(int resourceId) {
return ownerPool.get(resourceId);
}
}
资源拥有者池是基于多线程的。其中Map<Integer, List> ownerPool、Map<Integer, ResourceNodeInfo> nodePool; 读写存在线程安全。List、ResourceNodeInfo生成 都需要加DCL。