当前位置: 首页 > news >正文

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后&#xff0c;就表示定义了一个Dubbo服务&#xff0c;应用启动时Dubbo只要扫描到了DubboService&#xff0c;就会解析对应的类&#xff0c;得到服务相关的配置信息&#xff0c;比如&#xff1a; 1. 服务的类型&…...

浅谈React的虚拟DOM

React的虚拟DOM&#xff1a;揭秘高效渲染的秘密 在React中&#xff0c;虚拟DOM&#xff08;Virtual DOM&#xff09;是一个核心概念&#xff0c;它是React能够提供高效渲染和更新的关键。虚拟DOM是一个轻量级的JavaScript对象&#xff0c;表示真实的DOM树。通过使用虚拟DOM&am…...

linux上海康SDK安装并设置环境变量

将HCNetSDK下linux部分复制到客户端电脑/usr/lib/HCNetSDK下:sudo cp -r H /usr/lib/HCNetSDK H是我的文件夹&#xff0c;要把这个文件夹的内容复制到/usr/lib/HCNetSDK路径里。 编辑&#xff1a;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…...

什么是全域电商?有哪些电商代运营公司能做全域电商代运营?

什么是全域电商&#xff1f;有哪些电商代运营公司能做全域电商代运营&#xff1f; 随着电商行业的迅猛发展&#xff0c;传统的单一平台运营模式已经无法满足品牌多元化发展的需求。在此背景下&#xff0c;全域电商作为一种新兴的运营方式应运而生&#xff0c;成为越来越多品牌在…...

微信小程序上传pdf和显示

引用&#xff1a;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服务器&#xff08;多个mongod实例&#xff09;&#xff08;有不…...

PDF编辑的好东西

1.Eage浏览器 直接拖到浏览器中就ok了&#xff0c;这样读书的话是非常爽的&#xff0c;然后的话最近&#xff0c;也不知道学啥&#xff0c;vue开发网站&#xff0c;一开始的配置&#xff0c;也是给我难到了&#xff0c;所以没有办法&#xff0c;就随便找点书看看吧&#xff0c…...

块设备的两种访问方法的区别

概述 1.当我们运行类似于“dd if/dev/sdb1ofsdb1.img”的命令把整个/dev/sdb1裸分区复制到sdb1.img的时候&#xff0c;内核走的是def_blk_fops这个file_operations 2.另外一种方法是通过文件系统来访问块设备&#xff0c;file_operations的实现则位于文件系统内&#xff0c;文…...

java 泛型中的 ?

在 Java 泛型中&#xff0c;? 被称为通配符&#xff08;wildcard&#xff09;&#xff0c;它代表了未知的类型。使用通配符可以增加代码的灵活性&#xff0c;允许在不知道具体类型的情况下操作泛型类或接口。通配符主要有以下几种形式&#xff1a; 无界通配符&#xff08;Unbo…...

如何在jupyter notebook切换python环境

目录 参考链接 首先确保conda已经正常安装 conda --version 或者conda -V 以下请将“myenv”替换成自己的命名&#xff01;&#xff01;&#xff01; 1-查看虚拟环境目录 conda env list 2-创建虚拟环境命令 conda create -n myenv 或者 conda create --name myenv 3-激活虚拟环…...

用Python将Word文档转换为Markdown格式

Markdown作为一种轻量级标记语言&#xff0c;以其简洁的语法和广泛的兼容性&#xff0c;特别适合用于博客、技术文档和版本控制系统中的内容管理。而Word文档则因其强大的排版功能&#xff0c;常常成为文档制作的首选。然而&#xff0c;直接使用Word格式在某些平台上可能显得过…...

CSV 文件

CSV&#xff0c;全称为 Comma-Separated Values&#xff09;&#xff08;逗号分隔值&#xff09;&#xff0c;是一种常用的文本文件格式&#xff0c;用于存储表格数据&#xff0c;如电子表格或数据库。它采用纯文本形式&#xff0c;以逗号作为字段之间的分隔符&#xff0c;每行…...

SpringCloud核心组件(五)

文章目录 Gateway一. 概述简介1. Gateway 是什么2. 什么是网关?3.Gateway 和 Nginx 两个网关的区别什么是流量入口&#xff1f; 4.Gateway 能干嘛5.gateway 三大核心概念6.运行方式 二. 入门案例a.创建gateway模块&#xff0c;在pom.xml中引入依赖b.创建启动类GatewayApplicat…...

TCP为什么需要三次握手和四次挥手,有哪些需要注意的地方?

TCP&#xff08;传输控制协议&#xff09;是一种面向连接的、可靠的、基于字节流的传输层通信协议。为了确保数据能够准确无误地从一端发送到另一端&#xff0c;TCP设计了一系列机制来保证通信的可靠性&#xff0c;其中包括连接建立和断开的过程。 三次握手&#xff08;Three-…...

机器学习(基础2)

特征工程 特征工程:就是对特征进行相关的处理 一般使用pandas来进行数据清洗和数据处理、使用sklearn来进行特征工程 特征工程是将任意数据(如文本或图像)转换为可用于机器学习的数字特征,比如:字典特征提取(特征离散化)、文本特征提取、图像特征提取。 特征工程API 实例化…...

Cpolar 内网穿透使用

Cpolar登录地址&#xff1a;cpolar - secure introspectable tunnels to localhost 使用固定公网TCP连接ssh ssh -p端口号 用户名公网地址...

ThreadLocal 提供线程局部变量

ThreadLocal作用 相当于建立一个独立的空间&#xff0c;可以把使用频率高的任何类型的数据放到里面&#xff0c;方便调用用来存取数据&#xff1a;set()/get()使用ThreadLocal存储的数据&#xff0c;线程安全 ThreadLocal工具类 /*** ThreadLocal 工具类*/ SuppressWarnings(…...

MongoDB聚合管道数组操作

数组表达式运算符判断数组中是否包含元素( i n ) 并获取元素索引 ( in)并获取元素索引( in)并获取元素索引(indexOfArray) 一、初始化成员数据 db.persons.insertMany([{ "_id" : "1001", "name" : "张三", "fruits" : [ …...

大数据如何助力干部选拔的公正性

随着社会的发展和进步&#xff0c;干部选拔成为组织管理中至关重要的一环。传统的选拔方式可能存在主观性、不公平性以及效率低下等问题。大数据技术的应用&#xff0c;为干部选拔提供了更加全面、精准、客观的信息支持&#xff0c;显著提升选拔工作的科学性和公正性。以下是大…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

服务器--宝塔命令

一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行&#xff01; sudo su - 1. CentOS 系统&#xff1a; yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA

浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求&#xff0c;本次涉及的主要是收费汇聚交换机的配置&#xff0c;浪潮网络设备在高速项目很少&#xff0c;通…...

【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论

路径问题的革命性重构&#xff1a;基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中&#xff08;图1&#xff09;&#xff1a; mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

iview框架主题色的应用

1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题&#xff0c;无需引入&#xff0c;直接可…...