上一篇文章說了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源碼搞下來,把遍歷過程和讀寫過程加讀寫鎖。最近莫得時間,有時間更改後上代碼