guide-rpc-framework vs Dubbo 实现

📍 RPC 框架实现对比

🚀 服务启动阶段对比

流程步骤 简化版 RPC 框架实现 Dubbo 实现
1. 服务扫描 github.javaguide.provider.ServiceProvider#publishService - 手动注册 @RpcService 注解的服务 - 扫描指定包下的服务实现类 调用链路: NettyRpcServerMain.main() → NettyRpcServer.start() → ServiceProvider.publishService() → 扫描@RpcService注解 → 注册到本地服务映射 org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor#scanServiceBeans - 扫描 @DubboService 注解 - 使用 DubboClassPathBeanDefinitionScanner 扫描指定包 调用链路: Spring容器启动 → BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry() → scanServiceBeans() → DubboClassPathBeanDefinitionScanner.scan() → processScannedBeanDefinition()
2. 服务注册 github.javaguide.registry.ServiceRegistry#registerService - 将服务信息注册到 Zookeeper - 创建服务节点和数据 调用链路: ServiceProvider.publishService() → ServiceRegistry.registerService() → ZkServiceRegistryImpl.registerService() → CuratorFramework.create() → Zookeeper节点创建 org.apache.dubbo.registry.integration.RegistryProtocol#export - 导出服务到注册中心 org.apache.dubbo.registry.integration.RegistryProtocol#register - 注册服务到注册中心 调用链路: ServiceBean.export() → ServiceConfig.export() → RegistryProtocol.export() → doLocalExport() → register(registry, registeredProviderUrl) → registry.register(url)
3. 服务器启动 github.javaguide.remoting.transport.netty.server.NettyRpcServer#start - 启动 Netty 服务器监听请求 - 配置编解码器和处理器 调用链路: NettyRpcServerMain.main() → NettyRpcServer.start() → ServerBootstrap.bind() → ChannelInitializer.initChannel() → pipeline.addLast(handlers) org.apache.dubbo.remoting.transport.netty4.NettyServer#doOpen - 初始化和启动 Netty 服务器 org.apache.dubbo.remoting.transport.netty4.NettyServer#initServerBootstrap - 配置服务器参数 调用链路: DubboProtocol.export() → createServer() → Transporters.bind() → NettyTransporter.bind() → new NettyServer() → doOpen() → initServerBootstrap() → bootstrap.bind()

🔄 RPC 调用阶段对比

流程步骤 简化版 RPC 框架实现 Dubbo 实现
4. 代理拦截 github.javaguide.proxy.RpcClientProxy#invoke - 拦截方法调用,构建 RpcRequest - 调用 RpcRequestTransport.sendRpcRequest() 调用链路: 用户调用接口方法 → JDK动态代理拦截 → RpcClientProxy.invoke() → new RpcRequest() → rpcRequestTransport.sendRpcRequest() org.apache.dubbo.rpc.proxy.InvokerInvocationHandler#invoke - 拦截方法调用,构建 RpcInvocation - 调用 InvocationUtil.invoke(invoker, rpcInvocation) 调用链路: 用户调用接口方法 → JDK动态代理拦截 → InvokerInvocationHandler.invoke() → new RpcInvocation() → InvocationUtil.invoke()
5. 服务发现 github.javaguide.registry.ServiceDiscovery#lookupService - 从 Zookeeper 获取服务提供者列表 - 返回可用的服务地址 调用链路: RpcClientProxy.invoke() → ServiceDiscovery.lookupService() → ZkServiceDiscoveryImpl.lookupService() → CuratorFramework.getChildren() → 解析服务地址列表 org.apache.dubbo.registry.integration.RegistryDirectory#notify - 接收注册中心通知 org.apache.dubbo.registry.integration.RegistryDirectory#refreshOverrideAndInvoker - 更新服务提供者列表 调用链路: InvocationUtil.invoke() → clusterInvoker.invoke() → AbstractClusterInvoker.invoke() → list(invocation) → directory.list() → RegistryDirectory.doList()
6. 负载均衡 github.javaguide.loadbalance.LoadBalance#selectServiceAddress - 从服务地址列表中选择一个 - 支持随机、轮询等算法 调用链路: ServiceDiscovery.lookupService() → LoadBalance.selectServiceAddress() → RandomLoadBalance.selectServiceAddress() → 返回选中的服务地址 org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#select - 选择服务实例 org.apache.dubbo.rpc.cluster.LoadBalance#select - 负载均衡算法接口 调用链路: AbstractClusterInvoker.invoke() → initLoadBalance() → doInvoke() → select(loadbalance, invocation, invokers, selected) → doSelect() → loadbalance.select()
7. 请求编码 github.javaguide.serialize.Serializer#serialize - 序列化 RpcRequest 对象 - 支持 Kryo、Protostuff 等序列化 调用链路: LoadBalance.selectServiceAddress() → NettyRpcClient.sendRpcRequest() → RpcMessageEncoder.encode() → Serializer.serialize() → 序列化RpcRequest org.apache.dubbo.rpc.protocol.dubbo.DubboCodec#encodeRequestData - 编码请求数据 - 序列化 RpcInvocation 对象 调用链路: selectedInvoker.invoke() → DubboInvoker.doInvoke() → currentClient.request() → HeaderExchangeClient.request() → HeaderExchangeChannel.request() → NettyChannel.send() → DubboCodec.encode() → encodeRequestData()
8. 网络传输 github.javaguide.remoting.transport.netty.client.NettyRpcClient#sendRpcRequest - 通过 Netty 发送请求到服务端 调用链路: Serializer.serialize() → NettyRpcClient.sendRpcRequest() → Channel.writeAndFlush() → NettyClientHandler.channelRead() → CompletableFuture.complete() org.apache.dubbo.remoting.transport.netty4.NettyChannel#send - 通过 Netty 发送请求 调用链路: DubboCodec.encode() → NettyChannel.send() → writeQueue.enqueue() → channel.writeAndFlush() → Netty网络传输
9. 请求处理 github.javaguide.remoting.handler.RpcRequestHandler#handle - 处理 RPC 请求,反射调用目标方法 调用链路: Netty接收数据 → NettyRpcServerHandler.channelRead() → RpcMessageDecoder.decode() → RpcRequestHandler.handle() → ServiceProvider.getService() → Method.invoke() org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#reply - 处理请求,解码反序列化,执行反射调用 调用链路: Netty接收数据 → NettyServerHandler.channelRead() → DubboCodec.decode() → DecodeableRpcInvocation.decode() → DubboProtocol.reply() → getInvoker() → invoker.invoke() → 反射调用业务方法
10. 响应返回 github.javaguide.remoting.handler.RpcRequestHandler#handle - 构建 RpcResponse 并序列化返回 调用链路: Method.invoke() → new RpcResponse() → RpcMessageEncoder.encode() → Serializer.serialize() → Channel.writeAndFlush() org.apache.dubbo.rpc.protocol.dubbo.DubboCodec#encodeResponseData - 编码响应数据,序列化执行结果 调用链路: 业务方法执行完成 → 返回Result → DubboCodec.encode() → encodeResponseData() → 序列化结果 → NettyChannel.send()
11. 结果解析 github.javaguide.remoting.transport.netty.client.NettyRpcClient#sendRpcRequest - 接收响应并反序列化结果 调用链路: 客户端接收响应 → NettyClientHandler.channelRead() → RpcMessageDecoder.decode() → Serializer.deserialize() → CompletableFuture.complete() → 返回结果给用户 org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcResult#decode - 解码响应,反序列化结果 调用链路: 客户端接收响应 → NettyClientHandler.channelRead() → DubboCodec.decode() → DecodeableRpcResult.decode() → AsyncRpcResult.complete() → InvokerInvocationHandler返回结果

🔄 完整端到端调用链路对比

简化版 RPC 框架完整调用链路

scss 复制代码
用户调用 demoService.sayHello("world")
    ↓
JDK动态代理拦截
    ↓
RpcClientProxy.invoke()
    ↓
new RpcRequest(interfaceName, methodName, parameters, paramTypes, requestId)
    ↓
ServiceDiscovery.lookupService(rpcServiceName)
    ↓
ZkServiceDiscoveryImpl.lookupService() → CuratorFramework.getChildren()
    ↓
LoadBalance.selectServiceAddress(serviceAddresses)
    ↓
RandomLoadBalance.selectServiceAddress() → 返回选中地址
    ↓
NettyRpcClient.sendRpcRequest(rpcRequest, targetServiceUrl)
    ↓
RpcMessageEncoder.encode() → Serializer.serialize(rpcRequest)
    ↓
Channel.writeAndFlush(encodedRequest)
    ↓
【网络传输】
    ↓
NettyRpcServerHandler.channelRead()
    ↓
RpcMessageDecoder.decode() → Serializer.deserialize()
    ↓
RpcRequestHandler.handle(rpcRequest)
    ↓
ServiceProvider.getService(rpcRequest.getInterfaceName())
    ↓
Method.invoke(service, rpcRequest.getParameters())
    ↓
new RpcResponse(requestId, result)
    ↓
RpcMessageEncoder.encode() → Serializer.serialize(rpcResponse)
    ↓
Channel.writeAndFlush(encodedResponse)
    ↓
【网络传输】
    ↓
NettyClientHandler.channelRead()
    ↓
RpcMessageDecoder.decode() → Serializer.deserialize()
    ↓
CompletableFuture.complete(rpcResponse.getData())
    ↓
返回结果给用户

Dubbo 完整调用链路

scss 复制代码
用户调用 demoService.sayHello("world")
    ↓
JDK动态代理拦截
    ↓
InvokerInvocationHandler.invoke()
    ↓
new RpcInvocation(serviceModel, methodName, interfaceName, protocolServiceKey, parameterTypes, args)
    ↓
InvocationUtil.invoke(invoker, rpcInvocation)
    ↓
AbstractClusterInvoker.invoke(invocation)
    ↓
list(invocation) → RegistryDirectory.doList()
    ↓
routerChain.route() → 返回可用invokers列表
    ↓
initLoadBalance(invokers, invocation)
    ↓
doInvoke(invocation, invokers, loadbalance)
    ↓
select(loadbalance, invocation, invokers, selected)
    ↓
doSelect() → loadbalance.select(invokers, url, invocation)
    ↓
selectedInvoker.invoke(invocation)
    ↓
DubboInvoker.doInvoke()
    ↓
currentClient.request(inv, timeout)
    ↓
HeaderExchangeClient.request() → HeaderExchangeChannel.request()
    ↓
NettyChannel.send() → writeQueue.enqueue()
    ↓
DubboCodec.encode() → encodeRequestData()
    ↓
channel.writeAndFlush()
    ↓
【网络传输】
    ↓
NettyServerHandler.channelRead()
    ↓
DubboCodec.decode() → decodeBody()
    ↓
DecodeableRpcInvocation.decode()
    ↓
DubboProtocol.reply(channel, message)
    ↓
getInvoker(channel, inv) → invoker.invoke(inv)
    ↓
反射调用业务方法
    ↓
返回Result
    ↓
DubboCodec.encode() → encodeResponseData()
    ↓
NettyChannel.send()
    ↓
【网络传输】
    ↓
NettyClientHandler.channelRead()
    ↓
DubboCodec.decode() → decodeBody()
    ↓
DecodeableRpcResult.decode()
    ↓
AsyncRpcResult.complete()
    ↓
CompletableFuture返回结果
    ↓
InvokerInvocationHandler返回结果给用户

References

绯闻女友想看很久的Dubbo面试题:没看明白,定坑

github.com/apache/dubb...

相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
胡写代码3 天前
别再前后端各写一套表单校验了
java·后端
大勇前进3 天前
原生 PHP 还是 Laravel?小项目到底要不要上框架
后端
yuzhi_liu3 天前
我用 LangGraph4j 实现 Multi-Agent Supervisor
后端
alsmile3 天前
Node-RED 之外,国产规则引擎的新方案:基于标准语法,Go 先行实现
后端·开源·go
大白803 天前
PHP 内存溢出排查思路:看懂报错日志,精准定位问题
后端
二月龙3 天前
PHP 接口返回统一响应封装,让前后端对接更省心
后端
盖伦发发3 天前
软件工程SOLID 五大设计原则
后端·软件工程