SBT 快速了解

本贴最后更新于 2063 天前,其中的信息可能已经时过境迁

SBT 快速了解


1. SBT 目录结构和配置文件

1.1 目录结构

src/
  main/
    resources/
       <files to include in main jar here>
    scala/
       <main Scala sources>
    java/
       <main Java sources>
  test/
    resources
       <files to include in test jar here>
    scala/
       <test Scala sources>
    java/
       <test Java sources>

  以上是基本的目录结构,结构和 maven 等构件工具标准目录基本一样。但是 在项目根路径下会有一个 project 的目录,还有一个 build.sbt 的配置文件。
  先说下 project 这个目录,这个目录下一般会有 project/ target/ build.properties plugins.sbt 这四个东西,前俩是目录,后俩是文件。

  • project/ :SBT 主要借助项目根路径下的 project 目录中的一些内容来帮助我们构建项目的结构。而 project 中的结构是借助于其子目录 project 来构建的。这个地方理论上可以一直嵌套下去。

  • target/ :这里的内容应该就是给 SBT 用来构建项目用的。

  • build.properties :这里暂时就存了个 sbt 的版本,更多作用待发掘。

  • plugins.sbt : SBT 插件的默认安装位置。想安装什么插件,写到这个文件里,SBT 就会自动安装。例如:

addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.2")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.3")

  

1.2 配置文件

SBT 默认提供的配置文件是项目根目录下的 build.sbt 文件,通过这个文件来配置构建整个项目的信息。但是 还可以通过在 project 目录下的 scala 文件和 build.sbt 结合起来配置,但是 project 下的 scala 文件一定要继承 Build,才能被 SBT 认作为构建信息文件。最终 SBT 会将这两个文件中的内容合并到一起,作为整个项目的构建信息。


2. 配置构建信息

2.1 jar 包的依赖管理-引入 jar

  这应该是每个构件工具最基本的功能。如下

libraryDependencies += "com.typesafe.akka" % "akka-actor_2.12" % "2.5.6"
// 第一个字符串中的内容是`groupId`,第二个字符串中的内容是`artifactId`,最后一个是`version`

也可以写成下面这个样子

libraryDependencies += {
  "com.typesafe.akka" % "akka-actor_2.12" % "2.5.6"
  "com.typesafe.akka" % "akka-agent_2.12" % "2.5.6"
  "com.typesafe.akka" % "akka-cluster_2.12" % "2.5.6"
}

  

2.2 jar 包的依赖管理-排除 jar

有时候引入一个 jar 包,会被依赖引入其他 jar 包。造成 jar 冲突。这个时候就要排除掉造成冲突的 jar。如下:

libraryDependencies += {
 "net.sf.json-lib" % "json-lib" % "2.4" exclude("commons-beanutils", "commons-beanutils")
}

使用 exclude 可以排除不想引入的 jar。同样第一个参数是 groupId,第二个是 artifactId

2.3 jar 包的依赖管理-仓库中找不到 jar

有时候仓库中找不到指定的 jar,这个时候有两个办法,一个是指定本地的 jar,另一个是使用 from 去网络上下载指定的 jar。

1.添加本地 jar
首先在 build.sbt 中指定 unmanagedBase 的值,这样 SBT 在构建项目的时候会将这个目录的 jar 给添加到项目的 classpath 中。

unmanagedBase := baseDirectory.value / "lib"

指定 unmanagedBase 对应的路径为项目根目录下的 lib 目录。

2.使用 from,如下:

"com.typesafe.akka" % "akka-transactor-2.11" % "2.3.9" from "http://repo1.maven.org/maven2/com/typesafe/akka/akka-transactor_2.11/2.3.9/akka-transactor_2.11-2.3.9.jar"

2.4 jar 包的依赖管理-jar 包仓库地址

resolvers += Resolver.url("aliyun", url("http://maven.aliyun.com/nexus/content/groups/public/"))
resolvers += Resolver.url("typesafe", url("http://dl.bintray.com/typesafe/ivy-releases/"))
resolvers += Resolver.url("sbt-plugin", url("http://dl.bintray.com/sbt/sbt-plugin-releases/"))

3. 编译参数和启动参数

build.sbt 中, fork := true 时,sbt 执行 run 命令时会新启动一个 JVM 来给项目运行,如果 fork := false(默认为 false)时,项目运行时会在 sbt 运行的这个 JVM 上。

javacOptions ++= Seq("-encoding", "UTF-8")
javacOptions ++= Seq("-source", "1.8", "-target", "1.8")

javaOptions += "-noverify"
javaOptions += ("-Drebel.dirs=" + target.value / "scala-2.12/classes")
javaOptions += "-Drebel.disable_update=true"
javaOptions += "-Xms500m"
javaOptions += "-Xmx500m"
javaOptions += "-XX:+UseG1GC"
javaOptions += "-XX:MaxGCPauseMillis=100"

通过上面示例可以在项目编译或启动时做一些操作。这些参数通过 sbt 的命令都可以看到。如:

D:\gitRepos\SGameServer>sbt
"C:\Users\Administrator\.sbt\preloaded\org.scala-sbt\sbt\"1.0.2"\jars\sbt.jar"

[info] Loading project definition from D:\gitRepos\SGameServer\project
[info] Set current project to SGameServer (in build file:/D:/gitRepos/SGameServer/)
> show javaOptions
is windows platform
[info] * -noverify
[info] * -Drebel.dirs=D:\gitRepos\SGameServer\target\scala-2.12\classes
[info] * -Drebel.disable_update=true
[info] * -Xms500m
[info] * -Xmx500m
[info] * -XX:+UseG1GC
[info] * -XX:MaxGCPauseMillis=100
[info] * -agentpath:D:\gitRepos\SGameServer\jrebel64.dll
[success] Total time: 0 s, completed 2017-10-17 17:42:47

build.sbt 这个文件中还可以写逻辑代码,如:

lazy val switchTask = taskKey[String]("Switch Jrebel By Platform !")
switchTask := System.getProperty("os.name").toUpperCase
javaOptions += {
  if (switchTask.value.contains("WINDOWS")) {
    println("is windows platform")
    "-agentpath:" + baseDirectory.value / "jrebel64.dll"
  } else {
    println("is linux platform")
    "-agentpath:" + baseDirectory.value / "libjrebel64.so"
  }
}

通过这个可以在不同系统下给运行指定不同的参数。

3.1 编译项目和启动项目

编译:

在 sbt 的 console 中执行 compile 这个命令即可编译整个项目,若使用 ~ compile 可以实现当有文件改动并保存后进行自动编译。

启动:

在 sbt 中执行 runrunMain 都可以启动项目,前者不用指定程序入口,在 console 中,sbt 会将所以入口展示给你选择。后者需要指定程序入口。

至于停止运行项目,好像只有 Ctrl+C 来结束,而且 Linux 环境下,在 sbt 的 console 启动项目再执行 Ctrl+C 会将 sbt 进程与项目进程都给结束。但是 windows 环境下这样操作只能结束 sbt 进程。


4. SBT 插件

在 plugins.sbt 文件中可以进行插件添加。如下:

addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.2")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.3")

形式就是这个样子,第一个插件是可以将项目当前的 jar 依赖关系生产一个网页,方便查看和排查。第二个插件是用来将项目打成 jar 包的。更多功能和更多插件待发掘。

5. SBT Console

在项目的根路径是运行 sbt,进入 SBT 的控制台。通过 help 命令可以查看帮助。如:

> help
  about                                   Displays basic information about sbt and the build.
  tasks                                   Lists the tasks defined for the current project.
  settings                                Lists the settings defined for the current project.
 ......

SBT 的配置定义主要是在 Keys.scala 这个文件中,所以可以通过 sbtconsole 可以查看这些配置值,如:

> name
[info] SGameServer
> version
[info] 1.0
> baseDirectory
[info] D:\gitRepos\SGameServer
> unmanagedBase
[info] D:\gitRepos\SGameServer\lib
>

sbt console 中的 reload 命令可以将 构建信息重新载入 当前 sbt 环境,不管是 build.sbt 还是 build.scala 中的。所以改了构建信息后,需要在 console 中 reload 下才会生效。

6. SBT Tasks

SBT 中的 Tasks 部分,内容比较多。我们也可以自定义 task。查看所有任务:

> tasks

This is a list of tasks defined for the current project.
It does not list the scopes the tasks are defined in; use the 'inspect' command for that.
Tasks produce values.  Use the 'show' command to run the task and print the resulting value.

  compile           Compiles sources.
  doc               Generates API documentation.
  dependencyGraph   Prints the ascii graph to the console
  run               Runs a main class, passing along arguments provided on the command line.
  ......

单独使用 tasks 命令只能看到 SBT 提供的任务,使用 -v 参数可以看到我们自定义的参数。
在 sbt 直接指向任务名称即可调用任务,其实执行 compilerun 等命令就是在执行任务。这不过这些是 SBT 提供的任务而已。

自定义任务:

lazy val switchTask = taskKey[String]("Switch Jrebel By Platform !")
switchTask := System.getProperty("os.name").toUpperCase

在 console 直接调用 switchTask 这个任务就执行了。如:

> switchTask
[success] Total time: 0 s, completed 2017-10-17 18:03:48

最后

以上就是 SBT 的基本配置信息。其实 Keys.scala 这个文件很重要,如果有什么需求不知道怎么配置,可以看下这个类中的定义。Tasks 这块内容很多,也很有用,有时间可以多研究一下,每个任务可以配置自己的 Scope。但是好像任务一定要手动调用才能执行。插件也能帮我们省很多事。console 下的 help 提供基本的帮助。官方文档 +help+Keys.scala 应该就可以解决大部分问题。

http://www.scala-sbt.org/1.x/docs/index.html
https://unmi.cc/tag/sbt/
Issue #13 · ReactivePlatform/Notes

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...