在最近一段時間里,通過搜集有關資料加上自己的理解,設計了一款輕量級RPC,起了一個名字 lightWeightRPC 。它擁有一個RPC常見的基本功能。主要功能和特點如下: 利用Spring實現依賴註入與參數配置 利用Netty來實現客戶端與服務端的遠程通信 利用Hessian來實現序列化 設置Zo ...
在最近一段時間里,通過搜集有關資料加上自己的理解,設計了一款輕量級RPC,起了一個名字lightWeightRPC。它擁有一個RPC常見的基本功能。主要功能和特點如下:
- 利用Spring實現依賴註入與參數配置
- 利用Netty來實現客戶端與服務端的遠程通信
- 利用Hessian來實現序列化
- 設置Zookeeper作為註冊中心
- 新設監控器,通過心跳機制來判斷服務端與監控器的網路連接狀況,當出現不穩定時,認為服務端出現了問題,在註冊中心刪除相關的服務信息。
- 利用Netty的Promise來實現非同步的傳送
- 構建線程池來管理髮送的請求線程
- 添加服務緩存機制,在註冊中心宕機的情況下仍能進行服務消費。
- 支持服務擴展點發現機制(SPI),對Spring的SPI機制進行改進,解決了依賴註入問題。
- 在客戶端從註冊中心獲取服務時,添加監聽器,當註冊中心對應節點發生變化時通知客戶端修改本地緩存信息。
以上是lightWeightRPC的全部功能,本版本添加的內容就是最後一個功能,為服務節點添加監聽器。
因為之前在本地添加了持久化的緩存,當服務消費時會先從緩存中查找信息,查不到再到註冊中心查找,但是當服務地址等信息發生變化時,如果不對緩存信息進行修改就可能會發生錯誤。所以在本版本中為服務節點添加了監聽器。
如何添加監聽器
當客戶端首次從註冊中心獲取服務信息時,會對有關服務節點添加監聽器,具體方法在addListenerForService
,設置完監聽後,再獲取相關服務節點信息,並封裝在URL類中。
public static List<URL> getServiceInfo(String interfaceName) {
try {
addListenerForService(interfaceName);
System.out.println("開始查找服務節點:" + getPath(interfaceName));
List<String> urlList = client.getChildren().forPath("/" + interfaceName);
System.out.println("結果:" + urlList);
List<URL> result = new ArrayList<>();
for(String serviceUrl : urlList) {
String[] urls = serviceUrl.split(":");
String implClassName = get(interfaceName, serviceUrl);
System.out.println(implClassName);
result.add(new URL(urls[0], Integer.valueOf(urls[1]), interfaceName, implClassName));
}
return result;
} catch (Exception e) {
System.out.println(e);
e.printStackTrace();
}
return null;
}
在添加監聽器時主要是PathChildrenCache
類,當節點發生變化時會觸發childEvent
事件,根據不同的狀態採取不同的策略。
final PathChildrenCache childrenCache = new PathChildrenCache(client, getPath(serviceName), true);
//同步初始監聽點childrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
childrenCache.getListenable().addListener(new PathChildrenCacheListener(){
@Override
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception { if(event.getType().equals(PathChildrenCacheEvent.Type.INITIALIZED)) {
//建立完監聽
return;
}
//刪除遠程服務節點
if (event.getType().equals(PathChildrenCacheEvent.Type.CHILD_REMOVED)) {
String path = event.getData().getPath();
FileUtil fileUtil = new FileUtil(true);
fileUtil.alterServiceCache(serviceName, path);
}
至此,一個RPC設計完成了,有一些不足,希望大家多多指正。
項目地址: lightWeightRpc