经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring » 查看文章
基于Springboot+Netty实现rpc的方法 附demo
来源:jb51  时间:2022/2/28 13:24:09  对本文有异议

今天翻看了一下Netty相关的知识点,正好练练手,简单捣鼓了这个demo;这里简单梳理一下;

前提知识点:

Springboot、 Netty、动态代理(反射)、反射

项目整体结构如下:

 1.在父项目中引入相关依赖;

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web</artifactId>
  4. <version>2.3.2.RELEASE</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>io.netty</groupId>
  8. <artifactId>netty-all</artifactId>
  9. <version>4.1.48.Final</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>com.alibaba</groupId>
  13. <artifactId>fastjson</artifactId>
  14. <version>1.2.58</version>
  15. </dependency>
  16. <dependency>
  17. <groupId>org.slf4j</groupId>
  18. <artifactId>slf4j-log4j12</artifactId>
  19. <version>2.0.0-alpha1</version>
  20. </dependency>

2.服务提供模块整体结构如下:

 这里重点关注一下 RequestModel  ResponseModel 两个消息体类,

  1. @Data
  2. @AllArgsConstructor
  3. public class RequestModel {
  4. private String requestId;
  5. private String serviceName;
  6. private String methodName;
  7. private Class[] paramTypes;
  8. private Object[] paramValues;
  9. }
  1. @Data
  2. @AllArgsConstructor
  3. public class ResponseModel {
  4. private String responseId;
  5. private String serviceName;
  6. private String methodName;
  7. private String code;
  8. private String data;
  9. }

用于服务端和客户端的数据传输;再者就是关注 ServerChannelInboundHandler 中的 channelRead0() 报文解码处理;

  1. @Override
  2. protected void channelRead0(ChannelHandlerContext ctx, String msg) {
  3. StringBuilder sb = null;
  4. RequestModel result = null;
  5. try {
  6. // 报文解析处理
  7. sb = new StringBuilder();
  8. result = JSON.parseObject(msg, RequestModel.class);
  9. requestId = result.getRequestId();
  10. String serviceName = result.getServiceName();
  11. String methodName = result.getMethodName();
  12. Class[] paramType = result.getParamTypes();
  13. Object[] paramValue = result.getParamValues();
  14. System.out.println(serviceName + " " + methodName);
  15. String substring = serviceName.substring(serviceName.lastIndexOf(".") + 1);
  16. String s = substring.substring(0, 1).toLowerCase() + substring.substring(1);
  17. Object serviceObject = applicationContext.getBean(s);
  18. Method method = Class.forName(serviceName).getMethod(methodName, paramType);
  19. Object returnValue = method.invoke(serviceObject, paramValue);
  20. ResponseModel responseModel = new ResponseModel(requestId,serviceName,methodName,"200",JSON.toJSONString(returnValue));
  21. sb.append(JSON.toJSONString(responseModel));
  22. sb.append("\n");
  23. System.out.println(sb.toString());
  24. ctx.writeAndFlush(sb);
  25. } catch (Exception e) {
  26. ResponseModel responseModel = new ResponseModel(requestId,"","","500",e.getMessage());
  27. String errorCode = JSON.toJSONString(responseModel)+"\n";
  28. log.error(errorCode);
  29. ctx.writeAndFlush(errorCode);
  30. log.error("报文解析失败: " + e.getMessage());
  31. }
  32. }

客户端的模块代码如下; 

这里重点关注的是 ClientHandler 类中 channelRead0() 方法的处理

  1. @Override
  2. protected void channelRead0(ChannelHandlerContext ctx, String msg) {
  3. System.out.println("收到服务端消息: " + msg);
  4. ResponseModel responseModel = JSON.parseObject(msg,ResponseModel.class);
  5. String responseId = responseModel.getResponseId();
  6. Promise promise = LocalPromise.promiseMap.remove(responseId);
  7. if(promise != null){
  8. String code = responseModel.getCode();
  9. if(code.equals("200")){
  10. promise.setSuccess(responseModel.getData());
  11. }else{
  12. promise.setFailure(new RuntimeException(responseModel.getData()));
  13. }
  14. }
  15. }

AppStart 类中获取获取服务的处理;

  1. private <T> T getProxyService(Class<T> serviceClass) {
  2. Object service = Proxy.newProxyInstance(serviceClass.getClassLoader(), new Class[]{serviceClass}, new InvocationHandler() {
  3. @Override
  4. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  5. Channel channel = NettyClient.getChannel(host, port);
  6. RequestModel requestModel = new RequestModel("100001", method.getDeclaringClass().getName(), method.getName(), method.getParameterTypes(), args);
  7. channel.writeAndFlush(JSON.toJSONString(requestModel) + "\n");
  8. Promise promise = new DefaultPromise(channel.eventLoop());
  9. LocalPromise.promiseMap.put(requestModel.getRequestId(), promise);
  10. System.out.println(LocalPromise.promiseMap+">>>>>>>>>>>>");
  11. promise.await();
  12. if (promise.isSuccess()) {
  13. Class<?> returnType = method.getReturnType();
  14. return JSON.toJavaObject(JSON.parseObject(promise.getNow()+""),returnType);
  15. } else {
  16. System.out.println(promise.cause());
  17. return promise.cause();
  18. }
  19. }
  20. });
  21. return (T) service;
  22. }

 测试结果:

总结: 这个demo相对比较简单,但对于理解rpc 远程调用有一定帮助,最后分享一下这个代码地址:

nettydemo: netty springboot rpc远程调用demo

到此这篇关于基于Springboot+Netty实现rpc功能的文章就介绍到这了,更多相关Springboot Nett实现rpc内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号