• 详解 资源发现技术 的基本实现


    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


    心得体会:

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

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

  • 相关阅读:
    springboot springcloud zuul 过滤器
    springboot springcloud eureka 熔断器
    javaweb servlet filter
    maven nexus 搭建私服(二)
    springboot springcloud zuul 网关入门
    springboot springcloud 配置中心
    springboot springcloud eureka 入门
    java rabbitmq
    java jvm调优
    maven nexus 搭建私服(一)
  • 原文地址:https://www.cnblogs.com/codderYouzg/p/13542855.html
Copyright © 2020-2023  润新知