Dubbo源码解析-服务导出(四)
一、服务导出
当我们在某个接口的实现类上加上@DubboService后,就表示定义了一个Dubbo服务,应用启动时Dubbo只要扫描到了@DubboService,就会解析对应的类,得到服务相关的配置信息,比如:
1. 服务的类型,也就是接口,接口名就是服务名
2. 服务的具体实现类,也就是当前类
3. 服务的version、timeout等信息,就是@DubboService中所定义的各种配置
解析完服务的配置信息后,就会把这些配置信息封装成为一个ServiceConfig对象,并调用其export()方法进行服务导出,此时一个ServiceConfig对象就表示一个Dubbo服务。而所谓的服务导出,主要就是完成三件事情:
1. 确定服务的最终参数配置
2. 按不同协议启动对应的Server(服务暴露)
3. 将服务注册到注册中心(服务注册)
二、确定服务参数
一个Dubbo服务,除开服务的名字,也就是接口名,还会有很多其他的属性,比如超时时间、版本
号、服务所属应用名、所支持的协议及绑定的端口等众多信息。但是,通常这些信息并不会全部在@DubboService中进行定义,比如,一个Dubbo服务肯定是属于某个应用的,而一个应用下可以有多个Dubbo服务,所以我们可以在应用级别定义一些通用的配置,比如协议。
我们在application.properties中定义:

表示当前应用下所有的Dubbo服务都支持通过tri协议进行访问,并且访问端口为20880,所以在进行某个服务的服务导出时,就需要将应用中的这些配置信息合并到当前服务的配置信息中。另外,除开可以通过@DubboService来配置服务,我们也可以在配置中心对服务进行配置,比如在
配置中心中配置:
dubbo.service.org.apache.dubbo.samples.api.DemoService.timeout=5000
表示当前服务的超时时间为5s。所以在服务导出时,也需要从配置中心获取当前服务的配置,如果在@DubboService中也定义了timeout,那么就用配置中心的覆盖掉,配置中心的配置优先级更高。最终确定出服务的各种参数。
三、服务暴漏
服务暴露就是根据不同的协议启动不同的Server,比如dubbo协议启动的都是Netty,我们也主要是讲解dubbo协议。
protected synchronized void doExport() {if (unexported) {throw new IllegalStateException("The service " + interfaceClass.getName() + " has already unexported!");}if (exported) {return;}if (StringUtils.isEmpty(path)) {path = interfaceName;}doExportUrls();exported();}
继续进入到doExportUrls()方法里面,for循环ProtocolConfig进行服务的暴漏
for (ProtocolConfig protocolConfig : protocols) {String pathKey = URL.buildKey(getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), group, version);// In case user specified path, register service one more time to map it to path.repository.registerService(pathKey, interfaceClass);doExportUrlsFor1Protocol(protocolConfig, registryURLs);
}
例如暴漏的协议可以是dubbo,tri,http等,本节我们只讨论dubbo协议的暴漏,也是生产上用的最多的。下图就是当ProtocolConfig为dubbo协议时的信息
在服务暴漏的方法中有一个比较关键的入参,即url,通过buildUrl(protocolConfig, map)方法创建,其实就是提取一些配置信息得到,那么在后续exportUrl暴漏的过程中,会通过dubbo的SPI机制获取到url上面的信息,从而获取到真正的实现类完成服务的暴漏,注册等过程,这种做法在dubbo中屡见不鲜。
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {Map<String, String> map = buildAttributes(protocolConfig);// remove null key and null valuemap.keySet().removeIf(key -> key == null || map.get(key) == null);// init serviceMetadata attachmentsserviceMetadata.getAttachments().putAll(map);URL url = buildUrl(protocolConfig, map);//20881这里赋值exportUrl(url, registryURLs);
}
可以看下url具体长什么样:

一、本地暴漏
继续执行方法exportUrl,这里会进行exportLocal,也就是本地暴漏,这里又重新生成了一个injvm协议的url,通过这种方式的暴漏,允许在同一个 JVM 中进行直连调用,而不需要通过网络。

举个栗子:DemoService定义如下
@Service
public class DemoServiceImpl implements DemoService {@Overridepublic String sayHello(String name) {return "Hello " + name;}
}
如果同一个jvm内部服务消费者希望调用这个方法,服务消费者通过 protocol=“injvm”配置引用本地的 InJvm 服务。
@Reference(protocol = "injvm")
private DemoService demoService;
使用 InJvm 协议暴露服务在 Dubbo 中具有多种用途,包括提高性能、简化测试、方便应用内部模块间调用等。通过 InJvm 协议,可以在同一个 JVM 内快速高效地调用服务,无需网络开销,适用场景广泛且灵活。
二、远程暴漏
我们重点讲解下远程暴漏,也就是依据dubbo协议,在exportRemote方法中;最终来到最最核心的方法,这里的ref就是我们的原始service类,可以看到这里是通过动态代理的方式将其最终包装了一个Invoker,可想而知最终执行业务逻辑的还是ref,dubbo的一些强大的功能扩展就是在Invoker进行再次封装,Invoker也非常的重要。
private void doExportUrl(URL url, boolean withMetaData) {Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);if (withMetaData) {invoker = new DelegateProviderMetaDataInvoker(invoker, this);}Exporter<?> exporter = protocolSPI.export(invoker);exporters.add(exporter);
}
这行代码中的protocolSPI通过名字可以看出来他会动态的读取invoker属性中的url获取具体的类执行export方法,所以我们要时刻查看invoker中的url属性,
Exporter<?> exporter = protocolSPI.export(invoker);
当前也即表示目前是registry协议的暴漏,意思就是要将服务在注册中心,就是会将服务的url注册到zk上。

很明显下面判断UrlUtils.isRegistry(invoker.getUrl())会等于true,最终来到RegistryProtocol类的export方法中
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {if (UrlUtils.isRegistry(invoker.getUrl())) {return protocol.export(invoker);}FilterChainBuilder builder = getFilterChainBuilder(invoker.getUrl());return protocol.export(builder.buildInvokerChain(invoker, SERVICE_FILTER_KEY, CommonConstants.PROVIDER));
}
这个方法中代码比较多,我们只看几个关键步骤


1、doLocalExport,当执行到这个方法的时候,注意到此时url上的协议已经是dubbo了,也就是说接下来会根据providerUrl上面的协议去进行服务暴露了。

2、Registry registry = getRegistry(registryUrl)获取到注册中心实现类
3、register(registry, registeredProviderUrl)最终将url写到注册中心,供服务消费者订阅使用
关于服务注册部分,下面会进行详细解释,我们继续看dubbo协议的服务暴漏,那么就会来到DubboProtocol类中的export方法,这里将invoker传递给了DubboExporter然后返回,服务暴露的返回对象就是这个exporter。
下面还有一行openServer,这里就是去启动netty,因为要供消费者进行网络调用,所以netty启动后作为服务端能够接受消费端的传过来的信息,最终这些信息会传递到exporter中的invoker方法,由invoker方法中的ref完成业务逻辑最终再通过netty发送给消费端。
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {checkDestroyed();URL url = invoker.getUrl();// export service.String key = serviceKey(url);DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);openServer(url);optimizeSerialization(url);return exporter;
}
最终operServer会执行到下面的doOpen()方法,可以看到这里是标准的netty启动流程
protected void doOpen() throws Throwable {bootstrap = new ServerBootstrap();bossGroup = NettyEventLoopFactory.eventLoopGroup(1, EVENT_LOOP_BOSS_POOL_NAME);workerGroup = NettyEventLoopFactory.eventLoopGroup(getUrl().getPositiveParameter(IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS),EVENT_LOOP_WORKER_POOL_NAME);final NettyServerHandler nettyServerHandler = new NettyServerHandler(getUrl(), this);channels = nettyServerHandler.getChannels();boolean keepalive = getUrl().getParameter(KEEP_ALIVE_KEY, Boolean.FALSE);bootstrap.group(bossGroup, workerGroup).channel(NettyEventLoopFactory.serverSocketChannelClass()).option(ChannelOption.SO_REUSEADDR, Boolean.TRUE).childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE).childOption(ChannelOption.SO_KEEPALIVE, keepalive).childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelFuture channelFuture = bootstrap.bind(getBindAddress());channelFuture.syncUninterruptibly();channel = channelFuture.channel();}
至此服务暴漏过程结束。
四、服务注册(下个章节继续解析服务注册)
相关文章:
Dubbo源码解析-服务导出(四)
一、服务导出 当我们在某个接口的实现类上加上DubboService后,就表示定义了一个Dubbo服务,应用启动时Dubbo只要扫描到了DubboService,就会解析对应的类,得到服务相关的配置信息,比如: 1. 服务的类型&…...
浅谈React的虚拟DOM
React的虚拟DOM:揭秘高效渲染的秘密 在React中,虚拟DOM(Virtual DOM)是一个核心概念,它是React能够提供高效渲染和更新的关键。虚拟DOM是一个轻量级的JavaScript对象,表示真实的DOM树。通过使用虚拟DOM&am…...
linux上海康SDK安装并设置环境变量
将HCNetSDK下linux部分复制到客户端电脑/usr/lib/HCNetSDK下:sudo cp -r H /usr/lib/HCNetSDK H是我的文件夹,要把这个文件夹的内容复制到/usr/lib/HCNetSDK路径里。 编辑:vi ~/.bashrc 找到export,按 i 插入换行添加 export LD_LIBRARY_PATH$LD_LIB…...
【计算机网络】UDP网络程序
一、服务端 1.udpServer.hpp 此文件负责实现一个udp服务器 #pragma once#include <iostream> #include <string> #include <cstdlib> #include <cstring> #include <functional> #include <strings.h> #include <unistd.h> #incl…...
什么是全域电商?有哪些电商代运营公司能做全域电商代运营?
什么是全域电商?有哪些电商代运营公司能做全域电商代运营? 随着电商行业的迅猛发展,传统的单一平台运营模式已经无法满足品牌多元化发展的需求。在此背景下,全域电商作为一种新兴的运营方式应运而生,成为越来越多品牌在…...
微信小程序上传pdf和显示
引用:https://blog.csdn.net/qq_54027065/article/details/129854339 loadResume(){let that thisuni.showLoading({title:"下载中"})wx.downloadFile({url:url,success:(res)>{console.log(res,"res11111")if (res.statusCode 200){setTi…...
MongoDB分布式集群搭建----副本集----PSS/PSA
MongoDB分布式集群 Replication 复制、Replica Set 复制集/副本集 概念 一、 副本集的相关概念 1.概念 “ A replica set is a group of mongod instances that maintain the same data set. ” 一组MongoDB服务器(多个mongod实例)(有不…...
PDF编辑的好东西
1.Eage浏览器 直接拖到浏览器中就ok了,这样读书的话是非常爽的,然后的话最近,也不知道学啥,vue开发网站,一开始的配置,也是给我难到了,所以没有办法,就随便找点书看看吧,…...
块设备的两种访问方法的区别
概述 1.当我们运行类似于“dd if/dev/sdb1ofsdb1.img”的命令把整个/dev/sdb1裸分区复制到sdb1.img的时候,内核走的是def_blk_fops这个file_operations 2.另外一种方法是通过文件系统来访问块设备,file_operations的实现则位于文件系统内,文…...
java 泛型中的 ?
在 Java 泛型中,? 被称为通配符(wildcard),它代表了未知的类型。使用通配符可以增加代码的灵活性,允许在不知道具体类型的情况下操作泛型类或接口。通配符主要有以下几种形式: 无界通配符(Unbo…...
如何在jupyter notebook切换python环境
目录 参考链接 首先确保conda已经正常安装 conda --version 或者conda -V 以下请将“myenv”替换成自己的命名!!! 1-查看虚拟环境目录 conda env list 2-创建虚拟环境命令 conda create -n myenv 或者 conda create --name myenv 3-激活虚拟环…...
用Python将Word文档转换为Markdown格式
Markdown作为一种轻量级标记语言,以其简洁的语法和广泛的兼容性,特别适合用于博客、技术文档和版本控制系统中的内容管理。而Word文档则因其强大的排版功能,常常成为文档制作的首选。然而,直接使用Word格式在某些平台上可能显得过…...
CSV 文件
CSV,全称为 Comma-Separated Values)(逗号分隔值),是一种常用的文本文件格式,用于存储表格数据,如电子表格或数据库。它采用纯文本形式,以逗号作为字段之间的分隔符,每行…...
SpringCloud核心组件(五)
文章目录 Gateway一. 概述简介1. Gateway 是什么2. 什么是网关?3.Gateway 和 Nginx 两个网关的区别什么是流量入口? 4.Gateway 能干嘛5.gateway 三大核心概念6.运行方式 二. 入门案例a.创建gateway模块,在pom.xml中引入依赖b.创建启动类GatewayApplicat…...
TCP为什么需要三次握手和四次挥手,有哪些需要注意的地方?
TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。为了确保数据能够准确无误地从一端发送到另一端,TCP设计了一系列机制来保证通信的可靠性,其中包括连接建立和断开的过程。 三次握手(Three-…...
机器学习(基础2)
特征工程 特征工程:就是对特征进行相关的处理 一般使用pandas来进行数据清洗和数据处理、使用sklearn来进行特征工程 特征工程是将任意数据(如文本或图像)转换为可用于机器学习的数字特征,比如:字典特征提取(特征离散化)、文本特征提取、图像特征提取。 特征工程API 实例化…...
Cpolar 内网穿透使用
Cpolar登录地址:cpolar - secure introspectable tunnels to localhost 使用固定公网TCP连接ssh ssh -p端口号 用户名公网地址...
ThreadLocal 提供线程局部变量
ThreadLocal作用 相当于建立一个独立的空间,可以把使用频率高的任何类型的数据放到里面,方便调用用来存取数据:set()/get()使用ThreadLocal存储的数据,线程安全 ThreadLocal工具类 /*** ThreadLocal 工具类*/ SuppressWarnings(…...
MongoDB聚合管道数组操作
数组表达式运算符判断数组中是否包含元素( i n ) 并获取元素索引 ( in)并获取元素索引( in)并获取元素索引(indexOfArray) 一、初始化成员数据 db.persons.insertMany([{ "_id" : "1001", "name" : "张三", "fruits" : [ …...
大数据如何助力干部选拔的公正性
随着社会的发展和进步,干部选拔成为组织管理中至关重要的一环。传统的选拔方式可能存在主观性、不公平性以及效率低下等问题。大数据技术的应用,为干部选拔提供了更加全面、精准、客观的信息支持,显著提升选拔工作的科学性和公正性。以下是大…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...
【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...
【C++】纯虚函数类外可以写实现吗?
1. 答案 先说答案,可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...


