如何用Gradle Shadow插件重定位SPI服务并保留服务文件名?
使用Gradle Shadow插件重定位SPI并保留原服务文件名
不用额外做解压-修改-重打包的步骤,直接通过Shadow插件的自定义Transform机制就能实现需求。核心逻辑是:
- 正常配置类的重定位规则
- 对
META-INF/services下的服务文件,保留原文件名,但替换文件内容里的类全限定名为重定位后的名称
以下是完整的Gradle Groovy DSL配置示例:
plugins { id 'java' id 'com.github.johnrengelman.shadow' version '8.1.1' } repositories { mavenCentral() } shadowJar { // 配置类重定位:将some包下的类全部移到relocated包 relocate 'some', 'relocated' // 添加自定义Transform处理SPI服务文件 transform(com.github.jengelman.gradle.plugins.shadow.transformers.Transformer) { // 只处理META-INF/services目录下的文件 @Override boolean canTransformResource(FileTreeElement element) { return element.path.startsWith('META-INF/services/') } @Override void transform(TransformerContext context) { def input = context.inputStream.text // 替换原类名为重定位后的类名 def outputContent = input.replaceAll('some\\.Service', 'relocated\\.Service') // 写入修改后的内容,同时保留原文件路径 context.outputStream.write(outputContent.getBytes()) } @Override boolean hasTransformedResource() { return true } } // 确保不排除META-INF/services下的文件,让Transform能处理它们 exclude { false } }
关键细节说明:
- 类重定位规则:
relocate 'some', 'relocated'会自动将所有some包下的.class文件移动到relocated路径下,无需手动处理类文件。 - 自定义Transform:
canTransformResource方法过滤出需要处理的SPI服务文件transform方法读取文件内容,替换原类全限定名,再写入输出流,同时通过context.path保留原文件路径
- 排除策略:不要用排除规则跳过服务文件,否则Transform无法对其进行内容修改。
执行./gradlew shadowJar后,生成的JAR会完全符合需求:
- 原
/java/some/Service.class被重定位为/relocated/Service.class - 服务文件路径仍为
/META-INF/services/some.Service,但文件内容已替换为relocated.Service
内容的提问来源于stack exchange,提问作者lattitudesto
相关产品推荐
相关产品推荐

