基于Springboot+Netty實現(xiàn)rpc的方法 附demo
今天翻看了一下Netty相關(guān)的知識點,正好練練手,簡單搗鼓了這個demo;這里簡單梳理一下;
前提知識點:
Springboot、 Netty、動態(tài)代理(反射)、反射
項目整體結(jié)構(gòu)如下:
1.在父項目中引入相關(guān)依賴;
<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.服務(wù)提供模塊整體結(jié)構(gòu)如下:
這里重點關(guān)注一下 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; }
用于服務(wù)端和客戶端的數(shù)據(jù)傳輸;再者就是關(guān)注 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()); } }
客戶端的模塊代碼如下;
這里重點關(guān)注的是 ClientHandler 類中 channelRead0() 方法的處理
@Override protected void channelRead0(ChannelHandlerContext ctx, String msg) { System.out.println("收到服務(wù)端消息: " + 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 類中獲取獲取服務(wù)的處理;
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; }
測試結(jié)果:
總結(jié): 這個demo相對比較簡單,但對于理解rpc 遠程調(diào)用有一定幫助,最后分享一下這個代碼地址:
nettydemo: netty springboot rpc遠程調(diào)用demo
到此這篇關(guān)于基于Springboot+Netty實現(xiàn)rpc功能的文章就介紹到這了,更多相關(guān)Springboot Nett實現(xiàn)rpc內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一文教會你用mybatis查詢數(shù)據(jù)庫數(shù)據(jù)
MyBatis本身是一個數(shù)據(jù)庫連接框架,可以認為是JDBC的升級版,下面這篇文章主要給大家介紹了關(guān)于mybatis查詢數(shù)據(jù)庫數(shù)據(jù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下2022-04-04學(xué)會Java字節(jié)碼指令,成為技術(shù)大佬
Java 字節(jié)碼指令是 JVM 體系中非常難啃的一塊硬骨頭,我估計有些讀者會有這樣的疑惑,“Java 字節(jié)碼難學(xué)嗎?我能不能學(xué)會???”本文帶領(lǐng)大家一探究竟,幫助大家搞懂java底層代碼如何執(zhí)行2021-08-08JavaWeb Struts文件上傳功能實現(xiàn)詳解
這篇文章主要為大家詳細介紹了JavaWeb Struts文件上傳功能實現(xiàn)過程,思路清晰,供大家參考,感興趣的小伙伴們可以參考一下2016-06-06淺析Java中String與StringBuffer拼接的區(qū)別
String拼接會創(chuàng)建一個新的String對象,存儲拼接后的字符串,StringBuffer拼接是直接在本身拼接,會即時刷新。下面通過本文給大家介紹Java中String與StringBuffer拼接的區(qū)別,感興趣的朋友一起看看吧2017-06-06如何利用postman完成JSON串的發(fā)送功能(springboot)
這篇文章主要介紹了如何利用postman完成JSON串的發(fā)送功能(springboot),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07