SBT中如何通过Shading实现AWS SDK用旧版Netty、项目用新版?
解决AWS SDK与项目Netty版本冲突的SBT Shading配置方案
问题背景
项目里的SBT配置如下:
val awssdk2 = "2.15.14" val netty = "4.1.91.Final" ... "software.amazon.awssdk" % "kinesis" % Versions.awssdk2, "io.netty" % "netty-buffer" % Versions.netty
AWS SDK 2.15.14本身会依赖Netty 4.1.46.Final,但因为项目指定了更高的4.1.91.Final版本,依赖管理工具会自动用高版本覆盖低版本,结果导致AWS SDK与新Netty版本不兼容,抛出java.nio.channels.ClosedChannelException。
我们不想单独升级AWS SDK(项目构建文件规模庞大,需要通用的版本隔离机制),而是希望通过SBT的Shading功能实现版本隔离:让AWS SDK使用自身依赖的Netty 4.1.46.Final,项目其他代码(自研Netty逻辑、其他依赖Netty的库)则使用4.1.91.Final。
之前试过下面的Shading规则,但完全没用,仍出现相同错误:
assemblyShadeRules in assembly ++= Seq( ShadeRule.rename("io.netty.**" -> "aws2_version_of_netty.@1") .inLibrary("software.amazon.awssdk" % "kinesis" % Versions.awssdk2) ),
问题根源
之前的规则只针对kinesis这一个AWS SDK模块,但AWS SDK的Netty依赖分散在多个子模块中(比如netty-nio-client、http-client-spi等),仅给kinesis加规则覆盖不到所有用到Netty的AWS SDK代码;另外,也没处理项目全局Netty版本对AWS SDK依赖树的侵入。
正确配置方案
需要调整Shading规则,同时处理依赖排除和手动引入指定版本的Netty,具体配置如下:
// 第一步:给AWS SDK的kinesis排除所有Netty传递依赖,避免项目全局版本干扰 libraryDependencies ++= Seq( "software.amazon.awssdk" % "kinesis" % Versions.awssdk2 excludeAll( ExclusionRule(organization = "io.netty") ), // 手动引入AWS SDK原本依赖的Netty 4.1.46.Final全量模块 "io.netty" % "netty-buffer" % "4.1.46.Final" % "compile", "io.netty" % "netty-codec" % "4.1.46.Final" % "compile", "io.netty" % "netty-codec-http" % "4.1.46.Final" % "compile", "io.netty" % "netty-codec-http2" % "4.1.46.Final" % "compile", "io.netty" % "netty-common" % "4.1.46.Final" % "compile", "io.netty" % "netty-handler" % "4.1.46.Final" % "compile", "io.netty" % "netty-resolver" % "4.1.46.Final" % "compile", "io.netty" % "netty-transport" % "4.1.46.Final" % "compile", "io.netty" % "netty-transport-native-epoll" % "4.1.46.Final" % "compile" classifier "linux-x86_64", "io.netty" % "netty-transport-native-kqueue" % "4.1.46.Final" % "compile" classifier "osx-x86_64" ) // 第二步:配置Shading规则,把AWS SDK相关的Netty类全部重命名 assemblyShadeRules in assembly ++= Seq( ShadeRule.rename("io.netty.**" -> "aws2_version_of_netty.@1") // 覆盖所有AWS SDK中用到Netty的模块 .inLibrary("software.amazon.awssdk" % "kinesis" % Versions.awssdk2) .inLibrary("software.amazon.awssdk" % "netty-nio-client" % Versions.awssdk2) .inLibrary("software.amazon.awssdk" % "http-client-spi" % Versions.awssdk2) // 把手动引入的Netty 4.1.46.Final模块也加入规则,确保类被重命名 .inLibrary("io.netty" % "netty-buffer" % "4.1.46.Final") .inLibrary("io.netty" % "netty-codec" % "4.1.46.Final") .inLibrary("io.netty" % "netty-codec-http" % "4.1.46.Final") .inLibrary("io.netty" % "netty-codec-http2" % "4.1.46.Final") .inLibrary("io.netty" % "netty-common" % "4.1.46.Final") .inLibrary("io.netty" % "netty-handler" % "4.1.46.Final") .inLibrary("io.netty" % "netty-resolver" % "4.1.46.Final") .inLibrary("io.netty" % "netty-transport" % "4.1.46.Final") .inLibrary("io.netty" % "netty-transport-native-epoll" % "4.1.46.Final") .inLibrary("io.netty" % "netty-transport-native-kqueue" % "4.1.46.Final") // 确保项目中引用AWS SDK的代码能正确识别重命名后的类 .inProject )
配置说明
- 排除冲突传递依赖:给kinesis排除所有
io.netty的依赖,防止项目全局的Netty版本替换AWS SDK原本的依赖。 - 手动引入指定版本Netty:根据AWS SDK 2.15.14的依赖树,把它原本依赖的所有Netty子模块都手动引入,这些模块会被Shading重命名,和项目全局的Netty完全隔离。
- 扩展Shading规则范围:不能只给kinesis加规则,必须覆盖所有AWS SDK中用到Netty的子模块,同时把手动引入的Netty模块也加入,确保所有相关的Netty类都被重命名。
- .inProject标记:添加这个标记是为了确保项目中调用AWS SDK的代码能正确访问重命名后的Netty类(核心是修正AWS SDK内部的类引用)。
内容的提问来源于stack exchange,提问作者samthebest
相关产品推荐
相关产品推荐

