跳到主要内容
版本:Next

插件发现与类加载

为什么需要这篇文档

SeaTunnel 现有文档已经说明了 connector 怎么配置、二进制包里的依赖隔离目录怎么放,但还缺一个“从作业配置到插件实例”的运行时总览。

这篇文档解释的就是这条路径:

  • 配置里的插件名是如何变成一个 factory 实现的
  • 插件元数据是如何被发现的
  • connector jar 和依赖 jar 是如何被定位到的
  • 为什么类加载隔离尤其在 Zeta 里很关键

SeaTunnel 需要解决的问题

SeaTunnel 要支持大量 source、sink、transform、format 插件,运行时必须可靠地回答下面这些问题:

  • 用户配置对应的是哪个插件实现
  • 这个插件的 jar 和隔离依赖目录在哪里
  • 如何在不污染整个进程 classpath 的前提下加载它们
  • 如何把插件元数据暴露给 CLI、REST API 和 Web UI

如果没有插件发现与类加载这一层,connector 数量一多,很快就会出现依赖冲突和启动脆弱性问题。

运行时路径总览

一个插件从配置到执行,通常会经过下面这条链路:

作业配置
-> 解析插件名
-> 发现 factory
-> 校验 options
-> 定位 connector jar 与隔离依赖
-> 创建插件 classloader
-> 实例化 source / sink / transform
-> 在引擎运行时中执行

每一步的作用都不同:

  • discovery 负责找到正确实现
  • validation 负责提前拦截错误配置
  • jar resolution 决定哪些代码真正可用
  • classloader isolation 负责降低依赖冲突

插件发现模型

插件标识

运行时 SeaTunnel 会用一个逻辑标识来区分插件,通常会包含:

  • engine type
  • plugin type,例如 source 或 sink
  • plugin name

这个标识会被用于:

  • 配置解析
  • 插件查找
  • option 元数据暴露
  • 日志与诊断输出

Factory 发现

大多数用户可见插件都是通过 factory 接口创建的。实际运行时,SeaTunnel 主要依赖 Java SPI 和 factory discovery 工具,去加载 META-INF/services 下声明的实现。

典型例子包括:

  • TableSourceFactory
  • TableSinkFactory
  • transform factory
  • 某些 catalog / format factory

这也是为什么 connector 开发文档里会要求补 factory 注册与 service 元数据。

相关文档:

Jar 定位与打包

SeaTunnel 会把插件实现 jar 与 connector 专属的第三方依赖分开管理。

典型布局如下:

SEATUNNEL_HOME/
connectors/
connector-jdbc-<version>.jar
plugins/
connector-jdbc/
dependency-a.jar
dependency-b.jar

插件名与依赖目录之间的映射关系由 plugin-mapping.properties 管理。

这种设计带来两个直接收益:

  • connector 实现 jar 可以集中分发
  • connector 专属依赖可以彼此隔离

相关文档:

类加载的实际意义

为什么需要隔离

不同 connector 很可能依赖同一个第三方库的不同版本。如果所有 jar 都进入一个扁平 classpath,那么一个版本冲突就可能影响同一作业里的其他 connector。

类加载隔离主要在这三处体现价值:

  • connector 启动
  • task 部署
  • 多 connector 的长时间运行作业

目前最重要的实践差异是:SeaTunnel Engine(Zeta)对 connector 依赖隔离支持更强。现有隔离依赖文档已经明确提到,Spark 和 Flink 在运行期 classpath 共享更紧,因此混合版本场景风险更高。

这在下面几类问题里尤其关键:

  • 新增一个依赖树很重的 connector
  • 排查 ClassNotFoundExceptionNoSuchMethodError
  • 在分布式集群里打包和部署作业

元数据发现与 Option 暴露

插件发现不只是为了实例化运行时对象,它同时也支撑了元数据能力,例如通过 REST API 或 Web UI 暴露 connector 的 option 信息。

因此插件系统不仅要能发现 factory,还要能拿到这类元数据:

  • 支持的 plugin identifier
  • OptionRule
  • required / optional 字段
  • 参数分组与校验语义

相关文档:

常见失败模式

插件加载失败时,报错症状通常已经能说明是哪一层出了问题。

Discovery 失败

典型表现:

  • plugin not found
  • 文档里有这个 connector,但运行时识别不到

常见原因:

  • connector jar 缺失
  • SPI 注册缺失
  • plugin identifier 不匹配

Validation 失败

典型表现:

  • 作业提交前就失败
  • REST/UI 能看到元数据,但配置校验不过

常见原因:

  • 必填参数缺失
  • 互斥参数同时出现
  • 文档里的 option 名与 factory 定义不一致

Classpath / ClassLoader 失败

典型表现:

  • ClassNotFoundException
  • NoClassDefFoundError
  • NoSuchMethodError
  • 只在某个引擎上出现版本冲突

常见原因:

  • 依赖 jar 没放进 plugin 目录
  • connector 打包时带入了不兼容依赖
  • 集群节点之间的插件目录不一致

运维排查清单

当插件无法正确加载时,建议按这个顺序检查:

  1. connector jar 是否存在于二进制包中
  2. ${SEATUNNEL_HOME}/plugins/ 下的依赖目录是否正确
  3. plugin-mapping.properties 是否映射到了预期目录
  4. 集群各节点的插件布局是否一致
  5. 作业配置里的插件名是否与 factory identifier 完全一致
  6. 问题是否只在 Flink 或 Spark 发生,而 Zeta 正常

开发者检查清单

新增一个插件时,在怀疑引擎内部逻辑之前,建议先确认这些点:

  • factory 是否正确注册
  • factory identifier 是否与文档示例一致
  • OptionRule 是否覆盖 required / optional / exclusive 语义
  • connector 是否已经加入打包与 plugin mapping
  • 隔离依赖是否放在了预期的插件目录下

代码入口

建议从这些类开始看:

  • seatunnel-api/src/main/java/org/apache/seatunnel/api/table/factory/FactoryUtil.java
  • seatunnel-engine/seatunnel-engine-common/src/main/java/org/apache/seatunnel/engine/common/utils/FactoryUtil.java
  • seatunnel-engine/seatunnel-engine-core/src/main/java/org/apache/seatunnel/engine/core/classloader/ClassLoaderService.java
  • seatunnel-engine/seatunnel-engine-core/src/main/java/org/apache/seatunnel/engine/core/classloader/DefaultClassLoaderService.java
  • seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/rest/service/OptionRulesService.java

推荐阅读顺序

  1. 先读本页,建立运行时地图
  2. 再读 Connector 依赖隔离加载机制
  3. 再读 配置与 Option 系统
  4. 然后按需进入 Source Connector 开发指南Sink Connector 开发指南