You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Scala对象中从sbt的ProjectPlugin.scala获取应用Jar包名称?

获取Scala应用Jar包名称的可行方案

我来帮你梳理下这个问题的解决方案哈~首先得明确:你直接想在运行时的Scala代码里import ProjectPlugin.scala里的内容是行不通的,因为ProjectPlugin是sbt的构建定义代码,属于构建时的逻辑,根本不会被打包到你的应用Jar包里,运行时根本找不到这个类。下面给你几个实用的替代方案:

方案一:构建时自动生成包含name/version的源文件(最推荐)

这个方法能让运行时代码直接读取和构建配置完全同步的name和version,不用手动维护,非常可靠。

你可以在ProjectPlugin.scala里添加一个源码生成任务,让sbt在编译阶段自动生成一个包含项目信息的Scala对象:

import sbt._
import Keys._

object ProjectPlugin extends AutoPlugin {
  override def trigger = allRequirements
  override def projectSettings = Seq(
    // 自动生成AppInfo.scala到编译源目录
    sourceGenerators in Compile += Def.task {
      val outputDir = (sourceManaged in Compile).value
      val appInfoFile = outputDir / "com" / "yourcompany" / "AppInfo.scala"
      // 这里的name和version就是你在ProjectPlugin里定义的配置
      val content = s"""package com.yourcompany
                       |object AppInfo {
                       |  val name = "${name.value}"
                       |  val version = "${version.value}"
                       |}""".stripMargin
      // 写入文件
      IO.write(appInfoFile, content)
      Seq(appInfoFile)
    }.taskValue,
    // 你的原有配置
    name := "project1",
    version := "v1"
  )
}

之后在你的Test.scala里,就可以直接导入这个自动生成的对象来获取Jar名称了:

import com.yourcompany.AppInfo

object Test extends App {
  val jarName = s"${AppInfo.name}-${AppInfo.version}.jar"
  println(s"当前应用Jar名称:$jarName")
}

每次你更新ProjectPlugin里的version或者name,编译时都会自动生成最新的AppInfo.scala,完全同步,不会出错。

方案二:读取Jar包的Manifest元数据

sbt-assembly插件可以把项目的name和version写入Jar包的Manifest文件中,运行时通过类加载器读取这些元数据。

首先在ProjectPlugin.scala里配置assembly的Manifest属性:

import sbt._
import Keys._
import sbtassembly.AssemblyKeys._

object ProjectPlugin extends AutoPlugin {
  override def projectSettings = Seq(
    assemblyOption in assembly := (assemblyOption in assembly).value.copy(
      includeScala = false,
      // 把name和version写入Manifest
      manifest = (manifest in assembly).value
        .withAttribute("Implementation-Title", name.value)
        .withAttribute("Implementation-Version", version.value)
    ),
    // 原有配置
    name := "project1",
    version := "v1"
  )
}

然后在Test.scala里读取Manifest信息:

object Test extends App {
  val jarName = try {
    // 获取当前类所在的Jar包的Manifest
    val codeSource = classOf[Test].getProtectionDomain.getCodeSource
    val jarStream = codeSource.getLocation.openStream()
    val manifest = new java.util.jar.JarInputStream(jarStream).getManifest()
    jarStream.close()
    
    val appName = manifest.getMainAttributes.getValue("Implementation-Title")
    val appVersion = manifest.getMainAttributes.getValue("Implementation-Version")
    s"$appName-$appVersion.jar"
  } catch {
    case e: Exception => 
      // 处理非Jar运行的情况(比如IDE里调试)
      "unknown-app.jar"
  }
  
  println(s"当前应用Jar名称:$jarName")
}

这个方案不用生成额外的源文件,但要注意如果是在IDE里直接运行(不是打包成Jar),这段代码可能会抛出异常,需要加异常处理。

方案三:启动时传递系统属性(不推荐)

这个方法需要在启动Jar的时候手动传递name和version作为系统属性,比如:

java -Dapp.name=project1 -Dapp.version=v1 -jar project1-v1.jar

然后在Test.scala里读取系统属性:

object Test extends App {
  val appName = sys.props.getOrElse("app.name", "unknown")
  val appVersion = sys.props.getOrElse("app.version", "unknown")
  val jarName = s"$appName-$appVersion.jar"
  
  println(s"当前应用Jar名称:$jarName")
}

这个方案的缺点很明显:需要手动维护启动参数,容易和ProjectPlugin里的配置不一致,除非是特殊场景,否则不推荐使用。


内容的提问来源于stack exchange,提问作者user400058

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:49:00