上一篇文章说了ehcache基于RMI手动发现集群的搭建 https://blog.csdn.net/java_ying/article/details/103071571
但是手动发现有很多限制,比如不能动态增加机器,使用中有很多不方便
所以就根据ehcache的机制 加了一个轮询功能 类似心跳机制 去检查当前生效的链接
放代码前,先说一下思路:
ehcache 手动发现机制,在项目启动时 会读取xml配置文件的值,然后放到一个map里面。如下
操作是这个类操作的
就是简单的map操作而已
map里面 的键就是url 类似 //127.0.0.1:40009/articleCache 这样,值是一个date 我们暂时不用关心
RMICacheManagerPeerProvider 这个类提供了两个方法,分别是注册和反注册
/**
* Register a new peer
*
* @param rmiUrl
*/
public abstract void registerPeer(String rmiUrl);
/**
* Unregisters a peer
*
* @param rmiUrl
*/
public final synchronized void unregisterPeer(String rmiUrl) {
peerUrls.remove(rmiUrl);
}
我们就可以利用这两个方法来操作它
上文提到过 每次同步内容的时候 他都会遍历这个map 然后如果发送消息不成功会很浪费时间
我们就做一个监测功能,当我们配置文件的值不生效的时候 就unregisterPeer,如果生效了就registerPeer
这个provider 可以从CacheManager中拿到。放代码
package com.hqjl.communityserv.thread;
import com.hqjl.communityserv.bean.vo.SocketParam;
import com.hqjl.communityserv.cache.EhcacheManager;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.distribution.CacheManagerPeerProvider;
import net.sf.ehcache.distribution.RMICacheManagerPeerProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import java.net.Socket;
import java.util.*;
/**
* @author chunying
* @Date: 2019/11/14 0014
*/
@Configuration
@PropertySource(value= {"classpath:eh.properties"}, encoding = "utf-8")
public class RMIUrlsThread{
@Value("${rmiurls}")
private String rmiurls;
private static final Map<Integer, String> urls = new HashMap<>();
private static final Map<Integer, SocketParam> paramMap = new HashMap<>();
private static final String RMI_URLS = "rmiUrls";
private static Boolean flag = false;
public void loadProps() {
int key = 0;
String[] split = rmiurls.split("\\|");
//这里面根据url 取出IP 和port用于测试连接是否可用
for (String s : split) {
urls.put(key, s);
String substring = s.substring(2);
String[] splitS1 = substring.split("\\:");
String IP = splitS1[0];
String s2 = splitS1[1];
String[] s2Split = s2.split("\\/");
String port = s2Split[0];
SocketParam socketParam = new SocketParam(IP, Integer.parseInt(port));
paramMap.put(key, socketParam);
key++;
}
}
public void thread() {
new Thread(){
@Override
public void run() {
loadProps();
//这里面获取CacheManager 很简单 我没有放这个类。 不会的话看我前一篇文章
CacheManager cacheManager = EhcacheManager.getCacheManager();
Map<String, CacheManagerPeerProvider> cacheManagerPeerProviders = cacheManager.getCacheManagerPeerProviders();
cacheManagerPeerProviders.forEach((k,v)-> {
RMICacheManagerPeerProvider provider = (RMICacheManagerPeerProvider)v;
while(true) {
urls.forEach((key, url)-> {
SocketParam socketParam = paramMap.get(key);
Socket socket = null;
String IP = socketParam.getIp();
Integer port = socketParam.getPort();
try {
//测试连接是否可用
socket = new Socket(IP, port);
socket.close();
provider.registerPeer(url);
}catch(Exception e) {
provider.unregisterPeer(url);
}
});
System.out.println("执行一次");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}.start();
}
public static void main(String[] args) {
}
}
package com.hqjl.communityserv.bean.vo;
/**
* @author chunying
* @Date: 2019/11/15 0015
*/
public class SocketParam {
private String ip;
private Integer port;
public SocketParam(){}
public SocketParam(String ip, Integer port) {
this.ip = ip;
this.port = port;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
}
eh.properties中的值就是我copy了一份 xml中rmiurl的值 比较懒 不想解析xml。。。
这个方法会在项目启动完成后立刻执行,首先把properties中值读出来,放进我们准备好的map,
然后还有一个map 是初次加载时 解析出地址中的IP 和 port ,因为String 的相关操作还是有点耗时的,最好一次操作,一直使用。两个map的key是相同的 用的时候用key做关联。
thread方法,新建了一个不死的线程,里面先通过EhcacheManager 取出 RMICacheManagerPeerProvider
while(true) 保证一直运行,测试连接是否可用 使用java.net的socket 如果通了 说明 连接的机器在运行,那么就注册
如果没通,说明挂了或者没启动,直接反注册。 切记 记得close();
Sleep()方法 是心跳间隔时间,自由发挥即可。
好了 这是一个不完整的博客,这样操作虽然可以实现想要的功能,但是会有一个问题:
我们看这个Map 注意是个SynchronizedMap 这个东西是带操作锁的,一个只有一个线程可以操作他,如果在遍历时有更新操作,那么他会报错的。所以要处理这个问题,还要继续跟踪ehcache的同步机制,是怎么处理异常的。
后续会继续更新~
------------------------------------------------------------------分割线-------------------------------------------------------------------------------------
后续:准备把ehcache源码搞下来,把遍历过程和读写过程加读写锁。最近莫得时间,有时间更改后上代码