基于Netty实现自定义RPC框架

发布时间:2026/5/20 9:09:50

基于Netty实现自定义RPC框架 基于Netty实现自定义RPC框架1. 概述1.1 项目简介本项目是一个基于Netty和Spring Boot实现的轻量级RPC远程过程调用框架。通过该框架开发者可以像调用本地方法一样调用远程服务实现服务解耦和分布式部署。1.2 技术栈技术版本说明Java17语言基础Spring Boot2.7.6服务管理框架Netty4.x (由Spring Boot管理)高性能网络通信框架FastJSON1.2.83JSON序列化/反序列化CGLIB(Spring内置)高性能反射调用Lombok(Spring Boot管理)简化代码1.3 核心特性✅服务注册: 通过RpcService注解自动注册服务✅动态代理: JDK动态代理实现透明远程调用✅异步通信: Netty异步非阻塞IO模型✅序列化支持: FastJSON序列化/反序列化✅优雅关闭: 资源优雅释放机制2. 架构设计2.1 整体架构图┌─────────────────────────────────────────────────────────────────────────┐ │ RPC 框架架构图 │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────┐ ┌─────────────────────┐ │ │ │ Consumer │ │ Provider │ │ │ │ (rpc-consumer) │ │ (rpc-provider) │ │ │ ├─────────────────────┤ ├─────────────────────┤ │ │ │ ClientBootstrap │ │ ServerBootstrapApp │ │ │ │ │ │ │ │ │ │ │ │ ▼ │ │ ▼ │ │ │ │ RpcClientProxy │ │ RpcServer │ │ │ │ (JDK动态代理) │ │ (Netty服务端) │ │ │ │ │ │ │ │ │ │ │ │ ▼ │ │ ▼ │ │ │ │ RpcClient │ │ RpcServerHandler │ │ │ │ (Netty客户端) │ │ (服务注册处理) │ │ │ │ │ │ │ │ │ │ │ │ ▼ │ │ ▼ │ │ │ │ RpcClientHandler │ │ RpcService │ │ │ │ (请求发送响应) │ │ (服务实现类) │ │ │ └──────────┬──────────┘ └──────────┬──────────┘ │ │ │ │ │ │ │ Netty Socket │ │ │ └────────────────────────────────────┘ │ │ 网络传输层 │ └─────────────────────────────────────────────────────────────────────────┘2.2 模块划分模块职责核心文件rpc-api公共接口定义IUserService.java,RpcRequest.java,RpcResponse.java,User.javarpc-provider服务提供端RpcServer.java,RpcServerHandler.java,RpcService,UserServiceImpl.javarpc-consumer服务消费端RpcClient.java,RpcClientHandler.java,RpcClientProxy.java2.3 调用流程图客户端调用 网络传输 服务端处理 │ │ │ ▼ │ │ 1. 用户调用代理对象方法 │ │ │ │ │ ▼ │ │ 2. RpcClientProxy封装RpcRequest │ │ │ │ │ ▼ │ │ 3. 序列化并发送请求 ──────────────► │ ────────────────────────────► 4. RpcServerHandler接收请求 │ │ │ │ │ ▼ │ │ 5. 反序列化RpcRequest │ │ │ │ │ ▼ │ │ 6. CGLIB反射调用服务方法 │ │ │ │ │ ▼ │ │ 7. 封装RpcResponse │ │ │ │ │ ▼ │ │ 8. 序列化并返回响应 │ │ │ ▼ │ │ 9. RpcClientHandler接收响应 ◄─────── │ ◄─────────────────────────── │ │ │ │ ▼ │ │ 10. 反序列化RpcResponse │ │ │ │ │ ▼ │ │ 11. 返回结果给调用方 │ │3. 核心组件详解3.1 数据模型3.1.1 RpcRequest请求对象文件路径:rpc-api/src/main/java/com/weh/rpc/commom/RpcRequest.java字段类型说明requestIdString请求唯一标识UUIDclassNameString目标服务接口全限定名methodNameString调用方法名parameterTypesClass?[]参数类型数组parametersObject[]参数值数组3.1.2 RpcResponse响应对象文件路径:rpc-api/src/main/java/com/weh/rpc/commom/RpcResponse.java字段类型说明requestIdString对应请求的IDerrorString错误信息成功时为nullresultObject方法调用返回结果3.1.3 User数据传输对象文件路径:rpc-api/src/main/java/com/weh/rpc/pojo/User.java字段类型说明idInteger用户IDnameString用户姓名3.2 服务端核心组件3.2.1 RpcService注解文件路径:rpc-provider/src/main/java/com/weh/anno/RpcService.java用于标识需要暴露为RPC服务的类。服务启动时RpcServerHandler会扫描所有带有此注解的Bean并注册到服务缓存中。Target(ElementType.TYPE)// 只能用于类/接口Retention(RetentionPolicy.RUNTIME)// 运行时可获取publicinterfaceRpcService{}3.2.2 RpcServerHandler服务端处理器文件路径:rpc-provider/src/main/java/com/weh/handler/RpcServerHandler.java核心职责:服务注册: 实现ApplicationContextAware在Spring容器初始化时扫描RpcService注解的Bean请求处理: 继承SimpleChannelInboundHandlerString处理客户端请求反射调用: 使用CGLIB的FastClass和FastMethod进行高效方法调用关键代码解析:// 服务实例缓存key为接口全限定名privatestaticfinalMapString,ObjectSERVICE_INSTANCE_MAPnewConcurrentHashMap();// Spring容器初始化时自动注册服务OverridepublicvoidsetApplicationContext(ApplicationContextapplicationContext){MapString,ObjectbeanMapapplicationContext.getBeansWithAnnotation(RpcService.class);for(ObjectserviceBean:beanMap.values()){// 获取服务实现的第一个接口作为keyStringinterfaceNameserviceBean.getClass().getInterfaces()[0].getName();SERVICE_INSTANCE_MAP.put(interfaceName,serviceBean);}}// 处理客户端请求OverrideprotectedvoidchannelRead0(ChannelHandlerContextctx,Stringmsg){RpcRequestrequestJSON.parseObject(msg,RpcRequest.class);RpcResponseresponsenewRpcResponse();response.setRequestId(request.getRequestId());try{response.setResult(getResult(request));// 反射调用}catch(Exceptione){response.setError(e.getMessage());}ctx.writeAndFlush(JSON.toJSONString(response));}注意: 使用CGLIB反射在JDK 17环境下需要添加JVM参数--add-opens java.base/java.langALL-UNNAMED3.2.3 RpcServer服务端启动类文件路径:rpc-provider/src/main/java/com/weh/server/RpcServer.javaNetty服务端配置:BossGroup: 单线程负责接收客户端连接WorkerGroup: 默认CPU核数*2负责处理业务逻辑编解码器:StringDecoderStringEncoder字符串编解码优雅关闭: 实现DisposableBean接口Spring容器销毁时自动释放资源。3.3 客户端核心组件3.3.1 RpcClientProxy动态代理文件路径:rpc-consumer/src/main/java/com/weh/proxy/RpcClientProxy.java核心职责: 通过JDK动态代理实现透明的远程调用。代理流程:创建Proxy.newProxyInstance()生成代理对象在InvocationHandler.invoke()中封装RpcRequest创建RpcClient发送请求接收响应并反序列化返回publicstaticObjectcreateProxy(Class?serviceClass){returnProxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),newClass[]{serviceClass},(proxy,method,args)-{// 1. 封装请求RpcRequestrequestnewRpcRequest();request.setRequestId(UUID.randomUUID().toString());request.setClassName(method.getDeclaringClass().getName());request.setMethodName(method.getName());request.setParameterTypes(method.getParameterTypes());request.setParameters(args);// 2. 发送请求try(RpcClientclientnewRpcClient(127.0.0.1,8081)){Objectresponseclient.send(JSON.toJSONString(request));RpcResponserpcResponseJSON.parseObject(response.toString(),RpcResponse.class);// 3. 处理响应if(rpcResponse.getError()!null){thrownewRuntimeException(rpcResponse.getError());}returnJSON.parseObject(rpcResponse.getResult().toString(),method.getReturnType());}});}3.3.2 RpcClient客户端连接文件路径:rpc-consumer/src/main/java/com/weh/client/RpcClient.java关键配置:ChannelOption.SO_KEEPALIVE: 保持长连接ChannelOption.CONNECT_TIMEOUT_MILLIS: 连接超时3秒发送机制: 使用ExecutorService.submit()提交任务通过Future.get()阻塞等待响应。3.3.3 RpcClientHandler客户端处理器文件路径:rpc-consumer/src/main/java/com/weh/handler/RpcClientHandler.java线程同步机制: 实现Callable接口通过synchronizedwait/notify实现请求-响应同步// 发送请求后等待响应OverridepublicsynchronizedObjectcall()throwsException{context.writeAndFlush(requestMsg);wait();// 阻塞等待服务端响应returnresponseMsg;}// 收到响应后唤醒线程OverrideprotectedsynchronizedvoidchannelRead0(ChannelHandlerContextctx,Stringmsg){responseMsgmsg;notify();// 唤醒等待的线程}4. 使用说明4.1 服务端开发步骤1: 定义服务接口在rpc-api模块publicinterfaceIUserService{UsergetUserById(intid);}步骤2: 实现服务并添加注解RpcService// 标识为RPC服务ServicepublicclassUserServiceImplimplementsIUserService{OverridepublicUsergetUserById(intid){// 业务逻辑}}步骤3: 配置Netty端口netty:host:127.0.0.1port:8081步骤4: 启动服务运行ServerBootstrapApplication类。4.2 客户端开发publicclassClientBootstrap{publicstaticvoidmain(String[]args){// 创建代理对象IUserServiceuserService(IUserService)RpcClientProxy.createProxy(IUserService.class);// 像调用本地方法一样调用远程服务UseruseruserService.getUserById(1);System.out.println(user);}}5. 项目配置5.1 Maven依赖父pom.xml:propertiesspring-boot.version2.7.6/spring-boot.version/propertiesdependencies!-- Lombok --dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/dependency!-- FastJSON --dependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion1.2.83/version/dependency!-- Netty --dependencygroupIdio.netty/groupIdartifactIdnetty-all/artifactId/dependency/dependencies5.2 模块依赖关系rpc-provider └── rpc-api (依赖公共接口) rpc-consumer └── rpc-api (依赖公共接口)6. 运行验证6.1 启动服务端cdrpc-provider mvn spring-boot:run输出:服务端启动成功6.2 运行客户端cdrpc-consumer mvn exec:java-Dexec.mainClasscom.weh.ClientBootstrap7. 代码优化建议7.1 当前实现的局限连接管理: 当前每次调用创建新连接性能开销大服务发现: 硬编码服务地址缺乏服务注册中心序列化: 仅支持JSON可扩展Protobuf等高效序列化方案负载均衡: 不支持多服务实例的负载均衡异常处理: 错误处理较为简单7.2 优化方向优化项方案收益连接池使用Apache Commons Pool或Netty自带连接池减少连接创建开销服务注册中心集成ZooKeeper或Nacos动态服务发现序列化优化添加Protobuf支持提高传输效率负载均衡实现轮询/随机/加权算法支持多实例部署超时控制添加请求超时机制防止无限等待8. 总结本RPC框架基于Netty实现了核心的远程调用功能包含以下关键技术点Netty异步通信: 基于Reactor模式的高性能网络通信JDK动态代理: 实现透明的远程方法调用CGLIB反射: 高性能的方法调用实现JSON序列化: 简洁的数据传输格式Spring集成: 利用Spring容器管理服务Bean

相关新闻