zoukankan      html  css  js  c++  java
  • 详解 资源发现技术 的基本实现

    Youzg LOGO

    在本人之前的博文 《详解 服务发现 的基本实现》中,本人 详尽地 讲解了 服务发现 技术基本概念 以及 重要意义 等诸多知识点
    甚至在文章中 基本实现了 服务发现 技术

    那么,本篇博文 名为 资源发现技术,为什么本人要扯到 服务发现 技术 呢?

    服务发现 与 资源发现:

    1. 所谓的 “发现”,在我们的技术中,也就是 注册注销获取提供者列表 等操作
      因此,在很大程度上,两者的 实现思路 一致
    2. 资源,在 一定的程度上 来讲,就是 服务
      例如:电影视频、游戏数据 等
      上面的两个例子,都是 服务
      但是,在我们的角度上来分析,电影视频就是 视频资源,游戏数据就是 数据资源
      由上面两个例子来分析,其实 资源发现 就是 服务发现衍生体

    实现 原理:

    至于 实现原理,由于在 《详解 服务发现 的基本实现》中,本人已经 详尽地 解释过了,
    因此,在本篇博文中,本人就来 展示下基本的功能
    原理
    至于 资源信息的 注册注销资源信息的获取 等功能,由于只是执行一次
    因此,我们在此处采用 短链接模式,也就是 RMI技术 进行 网络通信


    那么,在 服务发现 的基础上,本人就来实现下 资源发现

    首先,本人来说明下 所需的 Jar包支持

    Jar包 支持:


    那么,下面本人就来在上面Jar包的基础上,来实现下 资源发现 技术:
    从技术的名称中,我们能够听得出:

    资源资源发现 技术 的核心

    那么,本人就先来实现下 有关资源 的类:

    资源:

    首先,本人来给出一个 自定义异常类 —— FileDoesNotExistException:

    目标路径不存在文件 异常 —— FileDoesNotExistException:

    package edu.youzg.resource_founder.exception;
    
    /**
     * 目标路径不存在 文件 异常
     */
    public class FileDoesNotExistException extends Exception {
        private static final long serialVersionUID = -6217840007725641732L;
    
        public FileDoesNotExistException() {
        }
    
        public FileDoesNotExistException(String message) {
            super(message);
        }
    
        public FileDoesNotExistException(String message, Throwable cause) {
            super(message, cause);
        }
    
        public FileDoesNotExistException(Throwable cause) {
            super(cause);
        }
    
    }
    

    本人再提供一个类,来表示 一个资源的身份

    资源 基本信息 实体类 —— ResourceBaseInfo:

    实现 思路:

    作为 标识资源 的类,最重要的是 能和其它资源区分开来
    那么,在这里,本人 以三个属性,来描述一个资源:

    • 服务器的名称
    • 该资源 在 服务器端 的 id
    • 该资源 的 版本号

    实现 代码:

    package edu.youzg.resource_founder.core;
    
    /**
     * 资源的基本信息<br/>
     * 服务器的名称、当前资源的id、当前资源的version
     */
    public class ResourceBaseInfo {
        private String app; // 服务器的名称
        private String id;  // 当前资源的 id
        private String version; // 当前资源的 版本号
    
        public ResourceBaseInfo(String app, String id, String version) {
            this.app = app;
            this.id = id;
            this.version = version;
        }
    
        public String getApp() {
            return this.app;
        }
    
        public void setApp(String app) {
            this.app = app;
        }
    
        public String getId() {
            return this.id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public String getVersion() {
            return this.version;
        }
    
        public void setVersion(String version) {
            this.version = version;
        }
    
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((app == null) ? 0 : app.hashCode());
            result = prime * result + ((id == null) ? 0 : id.hashCode());
            result = prime * result + ((version == null) ? 0 : version.hashCode());
            return result;
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            } else if (obj == null) {
                return false;
            } else if (this.getClass() != obj.getClass()) {
                return false;
            } else {
                ResourceBaseInfo other = (ResourceBaseInfo) obj;
                if (this.app == null) {
                    if (other.app != null) {
                        return false;
                    }
                } else if (!this.app.equals(other.app)) {
                    return false;
                }
    
                if (this.id == null) {
                    if (other.id != null) {
                        return false;
                    }
                } else if (!this.id.equals(other.id)) {
                    return false;
                }
    
                if (this.version == null) {
                    if (other.version != null) {
                        return false;
                    }
                } else if (!this.version.equals(other.version)) {
                    return false;
                }
    
                return true;
            }
        }
    
        @Override
        public String toString() {
            return "[" + this.app + "]" + this.id + ":" + this.version;
        }
    
    }
    

    既然表明了 资源的身份资源的内容信息 该如何获取呢?
    本人再来提供一个类来 封装资源的详细信息

    资源 详细信息 实体类 —— ResourceSpecificInfo:

    实现 思路:

    由于一个资源可能是目标资源的 子资源,因此需要一个 编号属性
    而且我们需要了解 该资源的地址,才能获取到该资源的内容信息
    并且 我们在 接收/发送 时也需要了解 该资源的 大小

    那么,依照上述思想,本人来给出实现代码

    实现 代码:

    package edu.youzg.resource_founder.core;
    
    import java.io.File;
    import java.io.Serializable;
    import java.util.Objects;
    
    import edu.youzg.resource_founder.exception.FileDoesNotExistException;
    
    /**
     * (单)子资源详细信息<br/>
     * 可能是目标文件的 子文件,也可能是目标文件<br/>
     * 文件编号、文件所在本地位置、文件大小
     */
    public class ResourceSpecificInfo implements Serializable {	// 序列化,防止fastjson转换失败
    	private static final long serialVersionUID = 7198662964849667723L;
    
    	private int fileNo; // 文件的编号
        private String filePath;    // 文件所在本地相对位置(相对根目录 的路径)
        private long fileSize;  // 文件大小
    
        public ResourceSpecificInfo() {
        }
    
        /**
         * 设置文件路径,<br/>
         * 并根据设置的文件路径,初始化成员属性
         * @param fileNo 文件编号
         * @param absoluteRoot 该文件 的根路径(可能是文件夹)
         * @param filePath 当前(子)文件路径
         * @throws FileDoesNotExistException
         */
        public void setFilePath(int fileNo, String absoluteRoot, String filePath) throws FileDoesNotExistException {
            this.fileNo = fileNo;
            String absoluteFilePath = absoluteRoot + filePath;  // 计算文件的 真实完整路径
            File file = new File(absoluteFilePath);
            if (!file.exists()) {
                throw new FileDoesNotExistException("文件[" + absoluteFilePath + "]不存在!");
            }
    
            this.filePath = filePath;
            this.fileSize = file.length();
        }
    
        public void setFileNo(int fileNo) {
            this.fileNo = fileNo;
        }
    
        public int getFileNo() {
            return fileNo;
        }
    
        public String getFilePath() {
            return filePath;
        }
    
        public long getFileSize() {
            return fileSize;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            ResourceSpecificInfo fileInfo = (ResourceSpecificInfo) o;
            return fileNo == fileInfo.fileNo;
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(fileNo);
        }
    
        @Override
        public String toString() {
            return fileNo + " : " + filePath + " : " + fileSize;
        }
    
    }
    

    那么,有了资源的信息,我们现在就来思考下 如何去实现 注册中心

    注册 中心:

    在上文中,本人讲过:

    注册中心 会提供 资源拥有者 节点信息注册注销
    以及 获取 目标资源的 拥有者节点信息列表获取 注册的资源目录 的功能

    那么,本人来给出一个 节点信息存储池,来方便我们管理 注册的资源拥有者节点

    节点信息存储池 —— NodePool:

    package edu.youzg.resource_founder.node;
    
    import java.util.Iterator;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    import org.apache.log4j.Logger;
    
    import edu.youzg.balance.INetNode;
    import edu.youzg.resource_founder.core.ResourceNodePool;
    import edu.youzg.util.Didadida;
    
    /**
     * 存储/删除节点,并可以扫描每一个存储的节点的健康情况:<br/>
     * 以当前节点 的hashcode为键,当前节点的节点信息为值,存储的map
     */
    public class NodePool {
        private static final long DEFAULT_DELAY_TIME = 3000L;
        private static final Map<Integer, INetNode> nodePool
        	= new ConcurrentHashMap();
        
        private static NodePool.ScanTimer scanTimer = new NodePool.ScanTimer(DEFAULT_DELAY_TIME);
    
        private static Logger log = Logger.getLogger(NodePool.class);
        
        public NodePool() {
        }
    
        /**
             * 开始扫描每一个节点
         */
        public static void startScanNode() {
            scanTimer.start();
        }
    
        /**
             * 停止扫描线程
         */
        public static void stopScanNode() {
            scanTimer.stop();
        }
    
        /**
             * 新增一个 资源拥有者 节点
         * @param node 资源拥有者 节点信息
         */
        public static void addNode(INetNode node) {
            int key = node.hashCode();
            if (!nodePool.containsKey(key)) {
                nodePool.put(key, new ResourceHolderNode(node));
            }
        }
    
        /**
             * 删除一个 资源拥有者 节点
         * @param node 资源拥有者 节点信息
         */
        public static void removeNode(INetNode node) {
            int key = node.hashCode();
            if (nodePool.containsKey(key)) {
                nodePool.remove(key);
            }
        }
    
        static class ScanTimer extends Didadida {
    
            public ScanTimer() {
            }
    
            public ScanTimer(long delay) {
                super(delay);
            }
    
            /**
                    * 心跳检测<br/>
                    * 保证 当前的列表 中 只保存 “活”的资源拥有者节点
             */
            @Override
            protected void doTask() {
                if (!NodePool.nodePool.isEmpty()) {
                    Iterator nodeList = NodePool.nodePool.values().iterator();
    
                    while (nodeList.hasNext()) {
                        INetNode node = (INetNode) nodeList.next();
    
                        try {
                            ((ResourceHolderNode) node).isActive();
                        } catch (Exception e) {
                        	log.warn("节点[" + node.getIp() + ":" + node.getPort() + "]异常宕机!注册中心已将其 拥有资源信息 注销!");
                            ResourceNodePool.logout(node);  // 当前节点 失活,注销该节点
                        }
                    }
                }
            }
    
        }
    }
    

    接下来,本人根据上面的类,来提供一个 资源-拥有者节点信息 映射池

    资源-拥有者 映射池 —— ResourceNodePool:

    package edu.youzg.resource_founder.core;
    
    import java.util.List;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.CopyOnWriteArrayList;
    
    import org.apache.log4j.Logger;
    
    import edu.youzg.balance.INetNode;
    import edu.youzg.resource_founder.node.NodePool;
    
    /**
     * 资源-拥有者 映射池:<br/>
     * 注册/注销 资源拥有信息、查询拥有者信息
     */
    public class ResourceNodePool {
        private static final Map<Integer, List<INetNode>> rnPool
                = new ConcurrentHashMap(); // 以 资源信息的hashcode 为键,该资源的拥有者list为值,存储map
        private static final List<ResourceBaseInfo> resourceList
                = new CopyOnWriteArrayList();   // 保存 已注册 的资源信息
    
        private static Logger log = Logger.getLogger(ResourceNodePool.class);
    
        /**
         * 注册 一个资源的拥有者 的信息
         * @param resourceInfo 目标资源
         * @param netNode 持有者的节点信息
         */
        public static void registry(ResourceBaseInfo resourceInfo, INetNode netNode) {
            int key = resourceInfo.hashCode();
            List<INetNode> addrList = null;
            synchronized (rnPool) {
                addrList = (List) rnPool.get(key);
                if (addrList == null) {
                    addrList = new CopyOnWriteArrayList();
                    rnPool.put(key, addrList);
                    resourceList.add(resourceInfo);
                }
            }
    
            addrList.add(netNode);
            NodePool.addNode(netNode);
        }
    
        /**
         * 注销 一个资源拥有者的 指定资源 信息
         * @param resourceInfo 目标资源
         * @param netNode 持有者的节点信息
         */
        public static void logout(ResourceBaseInfo resourceInfo, INetNode netNode) {
            int key = resourceInfo.hashCode();
            List<INetNode> addrList = null;
            synchronized (rnPool) {
                addrList = rnPool.get(key);
                if (addrList == null) {
                    // 日志:资源不存在异常!
                    log.error("资源["+ resourceInfo.toString() + "]不存在!");
                    return;
                }
                addrList.remove(netNode);
                if (addrList.isEmpty()) {
                    rnPool.remove(key);
                    resourceList.remove(resourceInfo);
                }
            }
        }
    
        /**
         * 注销 指定节点 的 所有资源
         * @param netNode 要注销的 节点
         */
        public static synchronized void logout(INetNode netNode) {
            int key = 0;
            List<INetNode> netNodes = null;
            for (ResourceBaseInfo resourceInfo : resourceList) {
                key = resourceInfo.hashCode();
                netNodes = rnPool.get(key);
                boolean remove = netNodes.remove(netNode);
                if (remove) {
                    if (netNodes.isEmpty()) {
                        rnPool.remove(key);
                        resourceList.remove(resourceInfo);
                    }
                }
            }
            NodePool.removeNode(netNode);
        }
    
        /**
         * 获取 指定资源 的节点列表
         * @param resourceInfo 目标资源
         * @return 该资源的 拥有者节点列表
         */
        public static synchronized List<INetNode> getAddressList(ResourceBaseInfo resourceInfo) {
            return rnPool.get(resourceInfo.hashCode());
        }
    
        /**
         * 获取 当前被注册的 资源列表
         * @return 当前被注册的 资源列表
         */
        public static List<ResourceBaseInfo> getResourceList() {
            return resourceList;
        }
    
    }
    

    那么,现在本人来给出一个 注册中心 功能接口

    注册中心 功能接口 —— IResourceCenter:

    package edu.youzg.resource_founder.center;
    
    import java.util.List;
    
    import edu.youzg.balance.DefaultNetNode;
    import edu.youzg.resource_founder.core.ResourceSpecificInfo;
    import edu.youzg.resource_founder.core.ResourceBaseInfo;
    
    /**
     * 注册中心 基本功能接口
     */
    public interface IResourceCenter {
        void registry(ResourceBaseInfo info, List<ResourceSpecificInfo> fileInfoList, DefaultNetNode netNode);
        void logout(ResourceBaseInfo res, DefaultNetNode addr);
        List<DefaultNetNode> getTotalAddressList(String recieveIp, int receivePort, ResourceBaseInfo res);
        List<ResourceSpecificInfo> getFileInfoListByResourceInfo(ResourceBaseInfo ri);
        List<ResourceBaseInfo> getResourceList();
    }
    

    那么,根据上文所给的 资源-拥有者 映射池
    本人现在来给出 注册中心 的 功能实现类

    注册中心 功能实现类 —— ResourceCenterImpl:

    package edu.youzg.resource_founder.center;
    
    import java.util.*;
    import java.util.concurrent.ConcurrentHashMap;
    
    import org.apache.log4j.Logger;
    
    import edu.youzg.balance.DefaultNetNode;
    import edu.youzg.balance.INetNode;
    import edu.youzg.resource_founder.core.ResourceSpecificInfo;
    import edu.youzg.resource_founder.core.ResourceBaseInfo;
    import edu.youzg.resource_founder.core.ResourceNodePool;
    
    /**
     * 注册中心 基本功能 实现类
     */
    public class ResourceCenterImpl implements IResourceCenter {
    	private Map<ResourceBaseInfo, List<ResourceSpecificInfo>> resourcePool
    		= new ConcurrentHashMap<ResourceBaseInfo, List<ResourceSpecificInfo>>();
    	
    	private Logger log = Logger.getLogger(ResourceCenterImpl.class);
    	
        public ResourceCenterImpl() {
        }
    
        @Override
        public void registry(ResourceBaseInfo info, List<ResourceSpecificInfo> fileInfoList, DefaultNetNode netNode) {
        	ResourceNodePool.registry(info, netNode);
            if (!this.resourcePool.containsKey(info)) {
            	this.resourcePool.put(info, fileInfoList);
            }
            log.info("节点" + netNode + ":资源[" + info + "]注册成功!");
        }
    
        @Override
        public void logout(ResourceBaseInfo info, DefaultNetNode netNode) {
            ResourceNodePool.logout(info, netNode);
            if (resourcePool.get(info).size() <= 0) {
    			resourcePool.remove(info);
    			log.info("资源[" + info + "]拥有者已全部注销,该资源当前不存在!");
    		}
            log.info("节点" + netNode + ":资源[" + info + "]注销成功!");
    
        }
    
        @Override
        public List<DefaultNetNode> getTotalAddressList(String recieveIp, int receivePort, ResourceBaseInfo res) {
        	log.info("节点[" + recieveIp + ":" + receivePort + "]:请求资源[" + res + "]");
            List<DefaultNetNode> result = new ArrayList<DefaultNetNode>();
    
            List<INetNode> nodeList = ResourceNodePool.getAddressList(res);
            if (nodeList == null || nodeList.isEmpty()) {
                return result;
            }
    
            for (INetNode node : nodeList) {
                result.add((DefaultNetNode) node);
            }
            return result;
        }
    
        @Override
        public List<ResourceBaseInfo> getResourceList() {
            return ResourceNodePool.getResourceList();
        }
    
    	@Override
    	public List<ResourceSpecificInfo> getFileInfoListByResourceInfo(ResourceBaseInfo ri) {
    		return this.resourcePool.get(ri);
    	}
    
    }
    

    在有些情况下,注册中心 需要 监听 资源拥有者 的健康状况
    因此,在这里,本人来提供一对 订阅者/发布者

    资源拥有者“健康状况” 发布者 —— IResourceSpeaker:

    package edu.youzg.resource_founder.core;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 资源信息发布者 接口
     */
    public interface IResourceSpeaker {
    
        /**
         * 增加 指定的订阅者
         * @param listener 目标订阅者
         */
        default void addListener(IResourceListener listener) {
            List<IResourceListener> listenerList = getListenerList();
            if (listenerList == null) {
                synchronized (IResourceSpeaker.class) {
                    listenerList = getListenerList();
                    if (listenerList == null) {
                        listenerList = new ArrayList<>();
                        setListenerList(listenerList);
                    }
                }
            }
            if (listenerList.contains(listener)) {
                return;
            }
            listenerList.add(listener);
        }
    
        /**
         * 移除 指定的订阅者
         * @param listener 指定的订阅者
         */
        default void removeListener(IResourceListener listener) {
            List<IResourceListener> listenerList = getListenerList();
            if (listenerList == null || !listenerList.contains(listener)) {
                return;
            }
            listenerList.remove(listener);
        }
    
        /**
         * 向所有订阅者 发布消息
         * @param message 要发布的消息
         */
        default void speakOut(String message) {
            List<IResourceListener> listenerList = getListenerList();
            if (listenerList == null || listenerList.isEmpty()) {
                return;
            }
            for (IResourceListener listener : listenerList) {
                listener.dealMessage(message);
            }
        }
    
        /**
         * 获取订阅者 列表
         * @return 订阅者 列表
         */
        List<IResourceListener> getListenerList();
    
        /**
         * 设置 订阅者 列表
         * @param listenerList 订阅者 列表
         */
        void setListenerList(List<IResourceListener> listenerList);
    
    }
    

    资源拥有者“健康状况” 订阅者 —— IResourceListener:

    package edu.youzg.resource_founder.core;
    
    /**
     * 资源信息订阅者 接口
     */
    public interface IResourceListener {
    	void dealMessage(String message);
    }
    

    那么,在以上诸类的基础上,本人来实现下 注册中心

    [核心]注册中心 —— ResourceRegistryCenter:

    在上文 实现原理 处,本人就讲过:

    对于 注册中心 的各种功能,均采用 短链接 模式 进行 网络通信

    由 上述思想 以及 前面的铺垫,本人来给出 注册中心 的代码:

    package edu.youzg.resource_founder.core;
    
    import edu.youzg.resource_founder.node.NodePool;
    import edu.youzg.rmi_impl.core.RMIFactory;
    import edu.youzg.rmi_impl.server.RMIServer;
    
    import java.util.List;
    
    /**
     * 资源注册中心:<br/>
     * 默认端口:6666<br/>
     * 配置文件名:ResourceRegistryCenter-RMI.xml
     */
    public class ResourceRegistryCenter implements IResourceSpeaker {
        private static final int DEFAULT_PORT = 6666;
        private static final String DEFAULT_CONFIG_PATH = "/resource/ResourceRegistryCenter-RMI.xml";
    
        private RMIServer rmiServer;
        private volatile boolean startup;
    
        private List<IResourceListener> listenerList;
    
        public ResourceRegistryCenter() {
            this(DEFAULT_PORT);
        }
    
        public ResourceRegistryCenter(int rmiServerPort) {
            this.rmiServer = new RMIServer();
            this.rmiServer.setRmiPort(rmiServerPort);
        }
    
        public void initRegistryCenter() {
            initRegistryCenter(DEFAULT_CONFIG_PATH);
        }
    
        public void initRegistryCenter(String configFilePath) {
            RMIFactory.scanRMIMapping(configFilePath);
        }
    
        public void setRmiServerPort(int rmiServerPort) {
            this.rmiServer.setRmiPort(rmiServerPort);
        }
    
        public void startup() {
            if (this.startup == true) {
                speakOut("注册中心 已启动");
                return;
            }
            this.startup = true;
            this.rmiServer.startUp();
            NodePool.startScanNode();
            speakOut("注册中心 启动成功");
        }
    
        public void shutdown() {
            if (this.startup == false) {
                speakOut("注册中心 已关闭");
                return;
            }
            this.startup = false;
            this.rmiServer.shutdown();
            NodePool.stopScanNode();
            speakOut("注册中心 关闭成功");
        }
    
        @Override
        public List<IResourceListener> getListenerList() {
            return listenerList;
        }
    
        @Override
        public void setListenerList(List<IResourceListener> listenerList) {
            this.listenerList = listenerList;
        }
    
    }
    

    注册中心设置好了,那么我们该如何去与注册中心通信呢?
    资源请求者资源拥有者 访问注册中心的流程 都是一样的
    因此,在这里,本人提供一个 资源处理器,来简化 与注册中心通信 的流程:

    资源处理器:

    资源处理器 —— Resourcer:

    package edu.youzg.resource_founder.resourcer;
    
    import edu.youzg.resource_founder.center.IResourceCenter;
    import edu.youzg.rmi_impl.client.RMIClient;
    
    /**
     * 封装 “访问 资源注册中心” 的基本属性
     */
    public class Resourcer {
        protected RMIClient rmiClient;  // 请求 资源注册中心
        protected IResourceCenter irc;  // 所要请求执行的方法 执行接口
    
        protected Resourcer() {
            this.rmiClient = new RMIClient();
            this.irc = this.rmiClient.getProxy(IResourceCenter.class);
        }
    
        public void setRmiServerIp(String rmiServerIp) {
            this.rmiClient.setRmiServerIp(rmiServerIp);
        }
    
        public void setRmiServerPort(int rmiServerPort) {
            this.rmiClient.setRmiServerPort(rmiServerPort);
        }
    
    }
    

    资源拥有者:

    作为一个 提供特殊功能网络节点,必须要有 节点信息
    但是,在给出 节点信息类 之前,本人要先来给出一个 具有 判断当前拥有者节点是否存活 功能接口 及其 实现类

    判断当前节点“是否存活” 功能接口 —— IResourceHolder:

    package edu.youzg.resource_founder.core;
    
    /**
     * 判断 当前资源拥有者是否存活
     */
    public interface IResourceHolder {
        default boolean isActive() throws Exception {
            return  false;
        }
    }
    

    接下来,是这个接口的实现类

    判断当前节点“是否存活” 功能实现类 —— ResourceHolderImpl:

    package edu.youzg.resource_founder.core;
    
    /**
     * 此类并未完成,若有需要,请使用者自行实现!
     * 判断 当前资源拥有者 是否 存活<br/>
     * 此处可以添加 负载均衡策略
     */
    public class ResourceHolderImpl implements IResourceHolder {
        public ResourceHolderImpl() {
        }
    
        @Override
        public boolean isActive() throws Exception {
            return false;
        }
    }
    

    在上面的接口和类的基础上,本人来给出 资源持有者 节点 封装类:

    资源持有者 节点 —— ResourceHolderNode:

    package edu.youzg.resource_founder.node;
    
    import edu.youzg.balance.DefaultNetNode;
    import edu.youzg.balance.INetNode;
    import edu.youzg.resource_founder.core.IResourceHolder;
    import edu.youzg.rmi_impl.client.RMIClient;
    
    /**
     * 资源持有者 节点:<br/>
     * 1. ResourceHolderNode(INetNode node) 初始化成员属性
     * 2. isActive()判断存活情况
     */
    public class ResourceHolderNode extends DefaultNetNode {
    
        private IResourceHolder resourceHolder;
    
        public ResourceHolderNode(INetNode node) {
            super(node.getIp(), node.getPort());
            RMIClient rmiClient = new RMIClient();
            rmiClient.setRmiServerIp(getIp());
            rmiClient.setRmiServerPort(getPort());
            this.resourceHolder = rmiClient.getProxy(IResourceHolder.class);
        }
    
        public boolean isActive() throws Exception {
            return resourceHolder.isActive();
        }
    
    }
    

    那么,本人在上面几个类的基础上,来实现下 资源拥有者

    [核心]资源拥有者 —— ResourceHolder:

    package edu.youzg.resource_founder.resourcer;
    
    import java.util.List;
    
    import edu.youzg.balance.DefaultNetNode;
    import edu.youzg.balance.INetNode;
    import edu.youzg.resource_founder.core.ResourceSpecificInfo;
    import edu.youzg.resource_founder.core.ResourceBaseInfo;
    import edu.youzg.rmi_impl.core.RMIFactory;
    import edu.youzg.rmi_impl.server.RMIServer;
    
    /**
     * 封装 资源持有者 的基本功能:<br/>
     * 默认 配置文件 全路径名:/resource/ResourceHolder-RMI.xml
     */
    public class ResourceHolder extends Resourcer {
        private static final String DEFAULT_CONFIG_PATH = "/resource/ResourceHolder-RMI.xml";
    
        private RMIServer rmiServer;
        private INetNode netNode;
    
        public ResourceHolder(String ip, int port) {
            this.netNode = new DefaultNetNode(ip, port);
            this.rmiServer = new RMIServer();
            this.rmiServer.setRmiPort(port);
            this.rmiServer.startUp();
        }
    
        /**
         * 通过扫描 默认路径的配置文件,初始化RMI工厂
         */
        public static void scanRMIMapping() {
            scanRMIMapping(DEFAULT_CONFIG_PATH);
        }
    
        /**
         * 通过扫描 指定路径的配置文件,初始化RMI工厂
         * @param mappingFile 指定的 配置文件路径
         */
        public static void scanRMIMapping(String mappingFile) {
            RMIFactory.scanRMIMapping(mappingFile);
        }
    
        public void setHolderIp(String ip) {
            this.netNode.setIp(ip);
        }
    
        public void setHolderPort(int serverPort) {
            this.rmiServer.setRmiPort(serverPort);
            this.netNode.setPort(serverPort);
        }
    
        /**
         * 开启 RMI服务器
         */
        public void startUp() {
            this.rmiServer.startUp();
        }
    
        /**
         * 注册一个资源 的持有信息
         * @param info 目标资源的信息
         */
        public void registry(ResourceBaseInfo info, List<ResourceSpecificInfo> fileInfoList) {
            this.irc.registry(info, fileInfoList, (DefaultNetNode)netNode);
        }
    
        /**
         * 注销一个资源 的持有信息
         * @param info 目标资源的信息
         */
        public void logout(ResourceBaseInfo info) {
            this.irc.logout(info, (DefaultNetNode) this.netNode);
        }
        
        /**
         * 关闭 RMI服务器
         */
        public void shutdown() {
            this.rmiServer.shutdown();
        }
    
    }
    

    最后,就是 资源请求者 了:

    资源请求者:

    作为 资源请求者,并没有太多的逻辑
    只需要 请求注册中心 所需要的信息 即可:

    [核心]资源请求者 —— ResourceRequester:

    package edu.youzg.resource_founder.resourcer;
    
    import edu.youzg.balance.DefaultNetNode;
    import edu.youzg.resource_founder.core.ResourceSpecificInfo;
    import edu.youzg.resource_founder.core.ResourceBaseInfo;
    
    import java.util.List;
    
    /**
     * 封装 资源请求者 的基本功能:<br/>
     * 1. setRmiServerIp() 和 setRmiServerPort()<br/>
     * 2. getAddressList(ResourceInfo res)<br/>
     * 3. getResourceList()
     */
    public class ResourceRequester extends Resourcer {
    
        public ResourceRequester() {
            super();
        }
    
        /**
         * 获取 目标资源的 拥有者列表
         * @param recieveIp 请求者ip
         * @param receivePort 请求者port
         * @param res 目标资源信息
         * @return 目标资源的 拥有者列表
         */
        public List<DefaultNetNode> getTotalAddressList(String recieveIp, int receivePort, ResourceBaseInfo res) {
            return irc.getTotalAddressList(recieveIp, receivePort, res);
        }
    
        /**获取 资源中心 当前持有的 资源列表
         * 
         * @return 资源中心 当前持有的 资源列表
         */
        public List<ResourceBaseInfo> getResourceList() {
            return irc.getResourceList();
        }
    
        /**
         * 根据 目标资源信息,获取 该资源的 子文件相对路径列表
         * @param ri 目标资源信息
         * @return 该资源的 子文件相对路径列表
         */
        public List<ResourceSpecificInfo> getFilePathListByResourceInfo(ResourceBaseInfo ri) {
    		return this.irc.getFileInfoListByResourceInfo(ri);
    	}
    
    }
    

    若有需要上述源码的同学,本人已将本文所讲解到的代码打成了Jar包:

    工具 Jar包:

    如有需要,请点击下方链接:
    Resource-Discovery


    心得体会:

    那么,到这里,资源发现 技术 就基本实现了
    我们在使用时,只需要将 资源拥有者 所拥有的 资源信息 注册
    再通过 资源请求者 请求 注册中心 即可!
    至于使用展示,将在本人之后的博文《【多文件自平衡云传输】专栏总集篇》中 进行巧妙地运用,
    并在最后会有视频展示,有兴趣的同学请前往围观哦!

    (最后,附上 本人《多文件自平衡云传输框架》专栏 展示视频的封面,希望大家多多支持哦!)
    视频展示

  • 相关阅读:
    NAT(网络地址转换)
    go从文件中读取json字符串并转换
    实现守护进程
    c++ uconcontext.h实现协程
    bzoj 1085骑士精神
    在线代码评测机
    基于时间轮的定时器
    内存管理(一)
    二叉树的先序中序后序(非递归)
    RDD操作
  • 原文地址:https://www.cnblogs.com/codderYouzg/p/13542855.html
Copyright © 2011-2022 走看看