4分钟
动态路由三组件启动时序分析
解析 DynamicArbHandler、DynamicRoutesCache、DataSyncWorker 三者的启动顺序与依赖关系,梳理主分片选主、轮询器注册、二进制客户端建立的全过程。
模块:
native-cloud-common-dynamic-routes+native-cloud-system-argument
一、启动顺序
三者不是靠注解排序启动的,而是靠 “getBean 强制依赖” 形成先后顺序:
DataSyncWorker @PostConstruct init() ──getBean──> DynamicRoutesCache setApplicationContext ──getBean──> DynamicArbHandler
(Ordered=102) (Ordered=101) (Ordered=100)
实际创建/初始化顺序:
- DynamicArbHandler(先完成
afterPropertiesSet→ 首次doArb选主) - DynamicRoutesCache(后完成
@PostConstruct init→ 注册轮询器 + 服务上下线监听) - DataSyncWorker(最后完成
@PostConstruct init→ 建立二进制客户端)
getOrder() 的 100/101/102 与依赖链方向一致,但 Spring 中 bean 创建顺序由依赖驱动,Ordered 在这里只是意图标识/列表排序用。
二、依赖关系
| 类 | 注册方式 | 依赖 | 强依赖点 |
|---|---|---|---|
DynamicArbHandler |
@EnableDynamicArb → Selector → DynamicArbConfiguration @Bean(@ConditionalOnBean(NacosConfigService)) |
NacosConfigService、NacosNamingService | 不依赖另外两个 |
DynamicRoutesCache |
@EnableDynamicRoutes → Selector → DynamicRoutesConfiguration @Bean |
DiscoveryClient、DynamicArbHandler | setApplicationContext 中 getBean(DynamicArbHandler.class) |
DataSyncWorker |
@Component(组件扫描) |
RestTemplate、DynamicRoutesCache | @PostConstruct init() 中 getBean(DynamicRoutesCache.class) |
三、加载时序流程图
sequenceDiagram
participant APP as 启动类
participant IOC as Spring 容器
participant ARB as DynamicArbHandler
(Ordered=100, InitializingBean) participant ROUTE as DynamicRoutesCache
(Ordered=101) participant SYNC as DataSyncWorker
(Ordered=102) participant NACOS as Nacos 配置/注册中心 Note over APP: @EnableDynamicArb → DynamicArbHandlerSelector → DynamicArbConfiguration
@EnableDynamicRoutes → DynamicRoutesSelector → DynamicRoutesConfiguration
@Component 扫描 DataSyncWorker rect rgb(235,245,255) Note over IOC,ARB: ① DynamicArbHandler 初始化 IOC->>ARB: 创建 bean(先建 nacosConfigService) ARB->>ARB: 构造器 ARB->>ARB: setApplicationContext / setEnvironment ARB->>ARB: afterPropertiesSet() ARB->>ARB: getHost() / initConfig() / initService() ARB->>NACOS: 检查 config serverStatus == "UP" alt gatewayEnabled || multiPartitionNo ARB->>ARB: new MasterWatchingManager(32) end alt !gatewayEnabled(业务程序) ARB->>ARB: doArb(dataId, false) —— 首次选主 ARB->>NACOS: getConfig(dataId, group) 嗅探 ARB->>NACOS: publishConfigCas 竞选主分片 ARB->>ARB: 成功→updateConfigSchedule()
→ UpdateConfigManager.doPolling() 心跳刷新
失败→subscribe 实例监听,主下线时 doArb(dataId,true) end end rect rgb(240,255,240) Note over IOC,ROUTE: ② DynamicRoutesCache 初始化 IOC->>ROUTE: 创建 bean ROUTE->>ROUTE: 构造器(routes 缓存初始化) ROUTE->>IOC: setApplicationContext → getBean(DynamicArbHandler)
【强制依赖:若 ① 未完成,此处同步触发其完整创建】 ROUTE->>ROUTE: setEnvironment ROUTE->>ROUTE: @PostConstruct init() ROUTE->>ARB: 读取 multiPartitionNo / gatewayEnabled / extendApplicationList ROUTE->>ROUTE: updateDynamicRoutes() ROUTE->>ARB: registerWorker(serviceName, partitionNo)
→ MasterWatchingWorker(3000).doPolling() 定时轮询主分片 ROUTE->>NACOS: registerServiceEvent() → NotifyCenter 订阅 InstancesChangeEvent end rect rgb(255,250,235) Note over IOC,SYNC: ③ DataSyncWorker 初始化(参数系统场景) IOC->>SYNC: 创建 bean(@Component) SYNC->>SYNC: 构造器 / setApplicationContext SYNC->>IOC: @PostConstruct init() → getBean(DynamicRoutesCache)
【强制依赖:若 ② 未完成,此处同步触发其完整创建】 SYNC->>IOC: getBean(RestTemplate) SYNC->>SYNC: initWorkers() SYNC->>ROUTE: getExtendApplicationList() / getUriWithApplication() SYNC->>下游: GET /ringBufferInner/port → new ClientWorker(二进制通信客户端) end
(Ordered=100, InitializingBean) participant ROUTE as DynamicRoutesCache
(Ordered=101) participant SYNC as DataSyncWorker
(Ordered=102) participant NACOS as Nacos 配置/注册中心 Note over APP: @EnableDynamicArb → DynamicArbHandlerSelector → DynamicArbConfiguration
@EnableDynamicRoutes → DynamicRoutesSelector → DynamicRoutesConfiguration
@Component 扫描 DataSyncWorker rect rgb(235,245,255) Note over IOC,ARB: ① DynamicArbHandler 初始化 IOC->>ARB: 创建 bean(先建 nacosConfigService) ARB->>ARB: 构造器 ARB->>ARB: setApplicationContext / setEnvironment ARB->>ARB: afterPropertiesSet() ARB->>ARB: getHost() / initConfig() / initService() ARB->>NACOS: 检查 config serverStatus == "UP" alt gatewayEnabled || multiPartitionNo ARB->>ARB: new MasterWatchingManager(32) end alt !gatewayEnabled(业务程序) ARB->>ARB: doArb(dataId, false) —— 首次选主 ARB->>NACOS: getConfig(dataId, group) 嗅探 ARB->>NACOS: publishConfigCas 竞选主分片 ARB->>ARB: 成功→updateConfigSchedule()
→ UpdateConfigManager.doPolling() 心跳刷新
失败→subscribe 实例监听,主下线时 doArb(dataId,true) end end rect rgb(240,255,240) Note over IOC,ROUTE: ② DynamicRoutesCache 初始化 IOC->>ROUTE: 创建 bean ROUTE->>ROUTE: 构造器(routes 缓存初始化) ROUTE->>IOC: setApplicationContext → getBean(DynamicArbHandler)
【强制依赖:若 ① 未完成,此处同步触发其完整创建】 ROUTE->>ROUTE: setEnvironment ROUTE->>ROUTE: @PostConstruct init() ROUTE->>ARB: 读取 multiPartitionNo / gatewayEnabled / extendApplicationList ROUTE->>ROUTE: updateDynamicRoutes() ROUTE->>ARB: registerWorker(serviceName, partitionNo)
→ MasterWatchingWorker(3000).doPolling() 定时轮询主分片 ROUTE->>NACOS: registerServiceEvent() → NotifyCenter 订阅 InstancesChangeEvent end rect rgb(255,250,235) Note over IOC,SYNC: ③ DataSyncWorker 初始化(参数系统场景) IOC->>SYNC: 创建 bean(@Component) SYNC->>SYNC: 构造器 / setApplicationContext SYNC->>IOC: @PostConstruct init() → getBean(DynamicRoutesCache)
【强制依赖:若 ② 未完成,此处同步触发其完整创建】 SYNC->>IOC: getBean(RestTemplate) SYNC->>SYNC: initWorkers() SYNC->>ROUTE: getExtendApplicationList() / getUriWithApplication() SYNC->>下游: GET /ringBufferInner/port → new ClientWorker(二进制通信客户端) end
四、关键机制说明
- DynamicArbHandler 最先行:
DynamicRoutesCache.setApplicationContext中getBean(DynamicArbHandler.class)会同步触发其完整创建,所以afterPropertiesSet(含首次doArb(false)竞选)必然在DynamicRoutesCache.init()之前完成——这也是"启动期两次选举"问题的基础时序。 - DynamicRoutesCache 承上启下:它从
DynamicArbHandler拿模式标志(gatewayEnabled/multiPartitionNo/extendApplicationList),并在updateDynamicRoutes()中反向调用registerWorker给每个分片注册MasterWatchingWorker轮询器。 - DataSyncWorker 最后:只有路由缓存和轮询器就绪后,
initWorkers()才能拿到"各分片主节点 URI",再调下游/ringBufferInner/port建二进制客户端;它只发主节点(备节点同步由主节点 redo 完成)。 MasterWatchingWorker.doPolling()首次轮询已改为同样走schedule延时(2026-08-17 修改),不再delay=0立即触发,避免启动窗口期重复选举。
五、关键代码位置索引
| 组件 | 方法 | 位置 |
|---|---|---|
| DynamicArbHandler | afterPropertiesSet() |
native-cloud-common/native-cloud-common-dynamic-routes/src/main/java/com/huang/DynamicArbHandler.java 第 102 行 |
| DynamicArbHandler | doArb(String, boolean) |
同文件第 145 行 |
| DynamicArbHandler | registerWorker(...) |
同文件第 495 行 |
| DynamicArbHandler | MasterWatchingWorker.doPolling() |
同文件第 872 行 |
| DynamicRoutesCache | setApplicationContext(getBean 强依赖) |
.../DynamicRoutesCache.java 第 97 行 |
| DynamicRoutesCache | @PostConstruct init() |
同文件第 75 行 |
| DynamicRoutesCache | updateDynamicRoutes() / registerServiceEvent() |
同文件第 117 / 205 行 |
| DataSyncWorker | @PostConstruct init() |
native-cloud-system-argument/src/main/java/com/huang/worker/DataSyncWorker.java 第 47 行 |
| DataSyncWorker | initWorkers() |
同文件第 68 行 |