dubbo源码分析二:服务发布
本文将深入分析dubbo的服务发布涉及到的流程及主要类的代码。首先,我们先从类的关系图来看一下dubbo发布服务涉及到的相关类。
1.类图
上图展示了部分服务发布过程中需要使用到的类和接口,其中:
spring适配涉及到的类:DubboNamespaceHandler、DubboBeanDefinitionParser、ServiceBean;
配置信息存储:ServicdConfig、RegistryConfig、MonitorConfig、ProtocolConfig、ProviderConfig等;
应用协议:Protocol、DubboProtocol、HessianProtocol、ThriftProtocol、RmiProtocol、AbstractProxyProtocol、AbstractProtocol等;
Server相关:Exchanger、HeaderExchanger、ExchangeServer、HeaderExchangeServer、Transporters、Transporter、NettyTransporter、NettyServer等;
2.时序图
我们通过时序图来分析一下在发布服务的过程中,上面的类是如何串联在一起的:
a.spring容器通过DubboBeanDefinitionParser类的对象来解析xml文件中的标签,生成ServiceConfig等配置对象;
b.ServiceConfig的export()等发布服务的方法被调用;
c.通过spi机制确定Protocol接口的实现对象为DubboProtocol的对象,调用它的openServer()等方法;
d.通过spi机制确定Transporter接口的实现对象为NettyTransporter,调用它的bind()方法;
e.调用NettyServer类,启动netty服务,绑定端口。
3.核心代码解析
a.DubboProtocol
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { URL url = invoker.getUrl(); //获取url信息 // export service. String key = serviceKey(url); //产生与发布的接口映射的key ,格式例如:com.alibaba.dubbo.demo.DemoService:20882 DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap); //创建DubboExporter对象 exporterMap.put(key, exporter); //缓存此对象 //export an stub service for dispaching event Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY,Constants.DEFAULT_STUB_EVENT); Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, false ); if (isStubSupportEvent && !isCallbackservice){ String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY); if (stubServiceMethods == null || stubServiceMethods.length() == 0 ){ if (logger.isWarnEnabled()){ logger.warn( new IllegalStateException( "consumer [" +url.getParameter(Constants.INTERFACE_KEY) + "], has set stubproxy support event ,but no stub methods founded." )); } } else { stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods); } } openServer(url); //打开服务 return exporter; } private void openServer(URL url) { // find server. String key = url.getAddress(); //client 也可以暴露一个只有server可以调用的服务。 boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true ); if (isServer) { ExchangeServer server = serverMap.get(key); if (server == null ) { serverMap.put(key, createServer(url)); //创建新的服务 } else { //server支持reset,配合override功能使用 server.reset(url); } } } private ExchangeServer createServer(URL url) { //默认开启server关闭时发送readonly事件 url = url.addParameterIfAbsent(Constants.CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString()); //默认开启heartbeat url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT)); String str = url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_SERVER); if (str != null && str.length() > 0 && ! ExtensionLoader.getExtensionLoader(Transporter. class ).hasExtension(str)) throw new RpcException( "Unsupported server type: " + str + ", url: " + url); url = url.addParameter(Constants.CODEC_KEY, Version.isCompatibleVersion() ? COMPATIBLE_CODEC_NAME : DubboCodec.NAME); ExchangeServer server; try { server = Exchangers.bind(url, requestHandler); } catch (RemotingException e) { throw new RpcException( "Fail to start server(url: " + url + ") " + e.getMessage(), e); } str = url.getParameter(Constants.CLIENT_KEY); if (str != null && str.length() > 0 ) { Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter. class ).getSupportedExtensions(); if (!supportedTypes.contains(str)) { throw new RpcException( "Unsupported client type: " + str); } } return server; } |
b.NettyServer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | protected void doOpen() throws Throwable { NettyHelper.setNettyLoggerFactory(); ExecutorService boss = Executors.newCachedThreadPool( new NamedThreadFactory( "NettyServerBoss" , true )); //boss线程池 ExecutorService worker = Executors.newCachedThreadPool( new NamedThreadFactory( "NettyServerWorker" , true )); //工作线程池 ChannelFactory channelFactory = new NioServerSocketChannelFactory(boss, worker, getUrl().getPositiveParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS)); bootstrap = new ServerBootstrap(channelFactory); //服务启动类 final NettyHandler nettyHandler = new NettyHandler(getUrl(), this ); channels = nettyHandler.getChannels(); // https://issues.jboss.org/browse/NETTY-365 // https://issues.jboss.org/browse/NETTY-379 // final Timer timer = new HashedWheelTimer(new NamedThreadFactory("NettyIdleTimer", true)); bootstrap.setPipelineFactory( new ChannelPipelineFactory() { public ChannelPipeline getPipeline() { NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec() ,getUrl(), NettyServer. this ); ChannelPipeline pipeline = Channels.pipeline(); /*int idleTimeout = getIdleTimeout(); if (idleTimeout > 10000) { pipeline.addLast("timer", new IdleStateHandler(timer, idleTimeout / 1000, 0, 0)); }*/ pipeline.addLast( "decoder" , adapter.getDecoder()); //增加解码器 pipeline.addLast( "encoder" , adapter.getEncoder()); //增加编码器 pipeline.addLast( "handler" , nettyHandler); //业务处理类 return pipeline; } }); // bind channel = bootstrap.bind(getBindAddress()); } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?