资源发现(下篇)

承接上篇:资源注册中心要实现对资源持有者的健康检查,那么他必须有所有已提交过注册的资源持有者节点地址。

此处的健康检查是采用定时的方式,去连接请求 资源持有者节点。

下面是自己做的一个定时器小工具:

public abstract class DiDaDiDa implements Runnable{
	private static final long DEFAULT_DELAY = 3000;
	private long delay;
	private Object lock;
	private volatile boolean goon;
	
	public DiDaDiDa() {
		this(DEFAULT_DELAY);
	}
	
	public DiDaDiDa(long delay) {
		this.delay = delay;
		this.lock = new Object();
	}

	public long getDelay() {
		return delay;
	}

	public abstract void doing();
	
	//启动定时器
	public void startUp() {
		if(goon == true) {
			return;
		}
		goon = true;
		new Thread(this, "定时器").start();
	}
	
	//关闭定时器
	public void stop() {
		if(goon == false) {
			return;
		}
		goon = false;
	}
	
	@Override
	public void run() {
		while(goon) {
			synchronized (lock) {
				try {
					lock.wait(delay);
					/*
					 * 注意此处是开一个线程执行doing,若直接执行那么定时是非常不准的,他会加上doing的
					 * 执行时间
					 */
					new InnerWoker();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	//开启线程执行doing()方法
	private class InnerWoker implements Runnable{
		
		public InnerWoker() {
			new Thread(this).start();
		}
		
		@Override
		public void run() {
			doing();
		}
		
	}
}

 说一下NodePool的数据结构:一对一结构。

  ConcurrentHashMap<Integer, DefaultNetNode>     键: DefaultNetNode对象的hashCode    值:DefaultNetNode对象

NodePool代码如下:

public class NodePool {
	private static final long DEFAULT_DELAY = 3000;
	private static final Map<Integer, DefaultNetNode> nodePool = 
			new ConcurrentHashMap<Integer, DefaultNetNode>();
	
	private static ScanTimer scanTimer = new ScanTimer(DEFAULT_DELAY);
	
	//开启定时扫面
	public static void startScanNode() {
		scanTimer.startUp();
	}
	
	public static void stopScanNode() {
		scanTimer.stop();
	}
	
	public static void add(DefaultNetNode node) {
		int key = node.hashCode();
		if(nodePool.containsKey(key)) {
			return;
		}
		nodePool.put(key, new ResourceHolderNode(node));
	}
	
	public static void remove(DefaultNetNode node) {
		int key = node.hashCode();
		if(nodePool.containsKey(key)) {
			nodePool.remove(key);
		}
	}
	
	static class ScanTimer extends DiDaDiDa{
		
		public ScanTimer() {
			super();
		}
		
		public ScanTimer(long delay) {
			super(delay);
		}
		
		@Override
		public void doing() {
			//扫描检测
			if(nodePool.isEmpty()) {
				return;
			}
			
			Iterator<DefaultNetNode> nodeList = nodePool.values().iterator();
			while(nodeList.hasNext()) {
				DefaultNetNode node = nodeList.next();
				//进行活跃检测
				ResourceHolderNode rhNode = (ResourceHolderNode) node;
				try {
					rhNode.isActive();
					System.out.println("正在检测 [" + rhNode + "]的活跃情况");
				} catch (Exception e) {
					//发现了非活跃资源持有者  将其删除
					ResourceNodePool.removeNode(node);
				}
			}
		}
		
	}
}

要想成功进行健康检测,那么资源注册中心必须能够主动连接资源持有者,即要利用RMIClient。此处的健康监测是在NodePool中进行的。故NodePool中存储的节点用DefaultNetNode(只有ip和port)是不行的。而是需要一个能够实在进行通信的网络节点,故在填充NodePool的时候存储的应该是ResourceHolderNode。

ResourceHolderNode:

public class ResourceHolderNode extends DefaultNetNode {
	private IResourceHolder resourceHolder;
	
	/**
	 * @param node	资源持有者的地址
	 */
	public ResourceHolderNode(DefaultNetNode node) {
		super(node.getIp(), node.getPort());
		RMIClient rmiClient = new RMIClient(node.getIp(), node.getPort());
		//设置连接时长
		rmiClient.setConnectTime(10);
		this.resourceHolder = rmiClient.getProxy(IResourceHolder.class);
	}
	
	//检测健康情况
	public boolean isActive() throws Exception {
		return resourceHolder.isActive();
	}
}

 接下来是真正的资源持有者ResourceHolder:

public class ResourceHolder extends Resourcer {
	private RMIServer rmiServer;
	private INetNode addr;
	
	public static void scanfRmiMapping(String filePath) {
		RMIFactory.scanRmiMapping(filePath);
	}
	
	public ResourceHolder(String ip, int port) {
		super();
		this.addr = new DefaultNetNode(ip, port);
		this.rmiServer = new RMIServer();
		this.rmiServer.setPort(port);
		this.rmiServer.startUp();
	}
	
	/**
	 * 	执行远程方法  注册资源
	 */
	public void registry(ResourceInfo resourceInfo) {
		irc.registry(resourceInfo, (DefaultNetNode)addr);
	}
	
	public void logout(ResourceInfo resourceInfo) {
		irc.logout(resourceInfo, (DefaultNetNode)addr);
	}
	
	public void shutdown() {
		this.rmiServer.shutdown();
	}
}

 对于资源请求者 其实它的实现很简单,他只需要向资源注册中心发送 “获取某资源对应的资源持有者集合”即可。

ResourceRequester:

public class ResourceRequester extends Resourcer{
	
	public ResourceRequester() {
		super();
	}

	public List<DefaultNetNode> getAddressList(ResourceInfo resourceInfo){
		return irc.getAddressList(resourceInfo);
	}
}

至此基本上就完成了整个“资源发现工具”的所有内容。

测试是必要的。利用两个测试类:

TestHolder:

public class TestHolder {
	/**
	 * 	此处的做法是定义两个资源  ri1和ri2	建立三个资源持有者 holder1(持有ri1) holder2(持有ri1) holder3(持有ri2)
	 */
	public static void main(String[] args) {
		ResourceInfo ri1 = new ResourceInfo("app", "1234567", "1.0");
		ResourceInfo ri2 = new ResourceInfo("app", "45757", "1.0");
		
		//建立资源注册中心---此处他会使用默认端口号54200
		ResourceRegistryCenter rrc = new ResourceRegistryCenter();
		rrc.startUp();
		
		ResourceHolder.scanfRmiMapping("/ResourceHolder.rmi.map.xml");
		ResourceHolder holder1 = new ResourceHolder("127.0.0.1", 54195);
		holder1.setRegistryIp("127.0.0.1");
		holder1.setRegistryPort(ResourceRegistryCenter.DEFAULT_PORT);
		holder1.registry(ri1);
		
		ResourceHolder holder2 = new ResourceHolder("127.0.0.1", 54190);
		holder2.setRegistryIp("127.0.0.1");
		holder2.setRegistryPort(ResourceRegistryCenter.DEFAULT_PORT);
		holder2.registry(ri1);
		
		ResourceHolder holder3 = new ResourceHolder("127.0.0.1", 54185);
		holder3.setRegistryIp("127.0.0.1");
		holder3.setRegistryPort(ResourceRegistryCenter.DEFAULT_PORT);
		holder3.registry(ri2);
	}

}

TestRequester:

public class TestRequester {
 
	public static void main(String[] args) {
		ResourceInfo ri1 = new ResourceInfo("app", "1234567", "1.0");
		
		//建立资源请求者并设置注册中心地址
		ResourceRequester requester = new ResourceRequester();
		requester.setRegistryIp("127.0.0.1");
		requester.setRegistryPort(ResourceRegistryCenter.DEFAULT_PORT);
		//资源请求者请求资源
		List<DefaultNetNode> nodeList = requester.getAddressList(ri1);
		if(nodeList.isEmpty()) {
			System.out.println("未发现该资源用有者");
		}else {
			System.out.println("发现资源拥有者如下:");
			for(DefaultNetNode node : nodeList) {
				System.out.println(node);
			}
		}
	}

}

先执行TestHolder可以看到输出结果:

再执行TestRequester结果:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值