基于Springboot+Netty實現(xiàn)rpc的方法 附demo
今天翻看了一下Netty相關的知識點,正好練練手,簡單搗鼓了這個demo;這里簡單梳理一下;
前提知識點:
Springboot、 Netty、動態(tài)代理(反射)、反射
項目整體結構如下:

1.在父項目中引入相關依賴;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.48.Final</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>2.0.0-alpha1</version>
</dependency>2.服務提供模塊整體結構如下:

這里重點關注一下 RequestModel 和 ResponseModel 兩個消息體類,
@Data
@AllArgsConstructor
public class RequestModel {
private String requestId;
private String serviceName;
private String methodName;
private Class[] paramTypes;
private Object[] paramValues;
}@Data
@AllArgsConstructor
public class ResponseModel {
private String responseId;
private String serviceName;
private String methodName;
private String code;
private String data;
}用于服務端和客戶端的數(shù)據(jù)傳輸;再者就是關注 ServerChannelInboundHandler 中的 channelRead0() 報文解碼處理;
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
StringBuilder sb = null;
RequestModel result = null;
try {
// 報文解析處理
sb = new StringBuilder();
result = JSON.parseObject(msg, RequestModel.class);
requestId = result.getRequestId();
String serviceName = result.getServiceName();
String methodName = result.getMethodName();
Class[] paramType = result.getParamTypes();
Object[] paramValue = result.getParamValues();
System.out.println(serviceName + " " + methodName);
String substring = serviceName.substring(serviceName.lastIndexOf(".") + 1);
String s = substring.substring(0, 1).toLowerCase() + substring.substring(1);
Object serviceObject = applicationContext.getBean(s);
Method method = Class.forName(serviceName).getMethod(methodName, paramType);
Object returnValue = method.invoke(serviceObject, paramValue);
ResponseModel responseModel = new ResponseModel(requestId,serviceName,methodName,"200",JSON.toJSONString(returnValue));
sb.append(JSON.toJSONString(responseModel));
sb.append("\n");
System.out.println(sb.toString());
ctx.writeAndFlush(sb);
} catch (Exception e) {
ResponseModel responseModel = new ResponseModel(requestId,"","","500",e.getMessage());
String errorCode = JSON.toJSONString(responseModel)+"\n";
log.error(errorCode);
ctx.writeAndFlush(errorCode);
log.error("報文解析失敗: " + e.getMessage());
}
}客戶端的模塊代碼如下;

這里重點關注的是 ClientHandler 類中 channelRead0() 方法的處理
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
System.out.println("收到服務端消息: " + msg);
ResponseModel responseModel = JSON.parseObject(msg,ResponseModel.class);
String responseId = responseModel.getResponseId();
Promise promise = LocalPromise.promiseMap.remove(responseId);
if(promise != null){
String code = responseModel.getCode();
if(code.equals("200")){
promise.setSuccess(responseModel.getData());
}else{
promise.setFailure(new RuntimeException(responseModel.getData()));
}
}
}和 AppStart 類中獲取獲取服務的處理;
private <T> T getProxyService(Class<T> serviceClass) {
Object service = Proxy.newProxyInstance(serviceClass.getClassLoader(), new Class[]{serviceClass}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Channel channel = NettyClient.getChannel(host, port);
RequestModel requestModel = new RequestModel("100001", method.getDeclaringClass().getName(), method.getName(), method.getParameterTypes(), args);
channel.writeAndFlush(JSON.toJSONString(requestModel) + "\n");
Promise promise = new DefaultPromise(channel.eventLoop());
LocalPromise.promiseMap.put(requestModel.getRequestId(), promise);
System.out.println(LocalPromise.promiseMap+">>>>>>>>>>>>");
promise.await();
if (promise.isSuccess()) {
Class<?> returnType = method.getReturnType();
return JSON.toJavaObject(JSON.parseObject(promise.getNow()+""),returnType);
} else {
System.out.println(promise.cause());
return promise.cause();
}
}
});
return (T) service;
}測試結果:


總結: 這個demo相對比較簡單,但對于理解rpc 遠程調用有一定幫助,最后分享一下這個代碼地址:
nettydemo: netty springboot rpc遠程調用demo
到此這篇關于基于Springboot+Netty實現(xiàn)rpc功能的文章就介紹到這了,更多相關Springboot Nett實現(xiàn)rpc內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Shiro 控制并發(fā)登錄人數(shù)限制及登錄踢出的實現(xiàn)代碼
本文通過shiro實現(xiàn)一個賬號只能同時一個人使用,本文重點給大家分享Shiro 控制并發(fā)登錄人數(shù)限制及登錄踢出的實現(xiàn)代碼,需要的朋友參考下吧2017-09-09
springboot中動態(tài)權限實時管理的實現(xiàn)詳解
這篇文章主要為大家詳細介紹了如何簡單實現(xiàn)一個在springboot中動態(tài)權限的實時管理,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下2024-10-10
Springboot項目出現(xiàn)java.lang.ArrayStoreException的異常分析
這篇文章介紹了Springboot項目出現(xiàn)java.lang.ArrayStoreException的異常分析,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-12-12
如何使用JDBC連接數(shù)據(jù)庫并執(zhí)行SQL語句
JDBC是Java數(shù)據(jù)庫連接的縮寫,是Java程序與數(shù)據(jù)庫進行交互的標準API。JDBC主要包括Java.sql和javax.sql兩個包,通過DriverManager獲取數(shù)據(jù)庫連接對象Connection,并通過Statement或PreparedStatement執(zhí)行SQL語句2023-04-04

