sbt Scala 的包管理工具

  • Simple Build Tool 简单的构建工具

一、安装与配置

1. 下载

  1. 1. 使用手动方式安装
  2. (http://www.scala-sbt.org/0.13/docs/zh-cn/Manual-Installation.html)
  3. 下载 sbt-launch.jar
  4. 2. 安装变量
  5. export SBT_HOME=/data/usr/sbt
  6. 1) 存放目录
  7. mv sbt-launch.jar $SBT_HOME
  8. sudo ln -s $SBT_HOME /usr/local/sbt
  9. 2) 编写 stb 执行文件
  10. vim $SBT_HOME/sbt
  11. #!/bin/bash
  12. # 这里是你的 JAVA_HOME 安装目录
  13. # JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk1.7.0_75.jdk/Contents/Home"
  14. SBT_OPTS="-Xms512M -Xmx1536M -Xss1M -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256M -Dsbt.ivy.home=${SBT_HOME}/ivy-repository -Dsbt.boot.directory=${SBT_HOME}/boot"
  15. $JAVA_HOME/bin/java $SBT_OPTS -jar `dirname $0`/sbt-launch.jar "$@"
  16. #增加执行权限
  17. chmod u+x $SBT_HOME/sbt
  18. 3) sbt 写入环境变量
  19. vim ~/.bashrc
  20. # SBT
  21. export PATH=$SBT_HOME:$PATH
  22. source ~/.bashrc
  23. 4) 创建仓库目录
  24. mkdir -p ${SBT_HOME}/ivy-repository
  25. mkdir -p ${SBT_HOME}/boot
  26. 2. 安装后查看版本
  27. sbt sbt-version : 第一次运行初始化会很久

二、构架与使用

1. 配置文件、运行模式介绍

  1. 1. 依赖管理
  2. 1) unmanaged dependencies 非托管的依赖性
  3. a) jar 包放到 lib 目录下即可
  4. // 非托管依赖
  5. unmanagedBase := baseDirectory.value / "lib"
  6. b) 更改存放路径
  7. unmanagedBase <<= baseDirectory { base => base / "3rdlibs" }
  8. 2) managed dependencies 依赖关系管理 (一般用这种方式)
  9. 采用 Apache Ivy 的依赖管理方式, 可以支持从 Maven 或者 Ivy Repository 中自动下载相应的依赖
  10. a) 格式
  11. libraryDependencies += groupID % artifactID % revision
  12. : libraryDependencies += "org.apache.derby" % "derby" % "10.4.1.3"
  13. b) 实际案例
  14. libraryDependencies += "org.apache.derby" % "derby" % "10.4.1.3" % "test" 允许我们限定依赖的范围只限于测试期间
  15. libraryDependencies += "org.apache.derby" % "derby" % "10.4.1.3" exclude("org", "artifact") 允许我们排除递归依赖中某些我们需要排除的依赖
  16. libraryDependencies += "org.apache.derby" %% "derby" % "10.4.1.3"
  17. 等同于"org.apache.derby" %% "derby_2.9.2" % "10.4.1.3",这种方式更多是为了简化同一依赖类库存在有多个 Scala 版本对应的发布的情况
  18. libraryDependencies ++= Seq("org.apache.derby" %% "derby" % "10.4.1.3",
  19. "org.scala-tools" %% "scala-stm" % "0.3",
  20. ...)
  21. 一次添加多个依赖
  22. 2. Resovers 多资源管理
  23. 1) 增加远程资源 (可以增加 git 依赖)
  24. resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"
  25. 2) 增加本地源
  26. resolvers += "Local Maven Repository" at "file:///usr/local/maven/repository"
  27. resolvers += "Local Maven Repository" at "file://"+Path.userHome.absolutePath+"/.m2/repository"
  28. 3. sbt 项目的 build 文件类型
  29. 1) 对于一个SBT项目来说,SBT在构建的时候,只关心两点
  30. a) build 文件的类型(是 *.sbt OR *.scala
  31. b) build 文件的存放位置
  32. .sbt .scala 二者之间的 settings(设置) 是可互相访问的
  33. .scala 中的内容会被 import .sbt
  34. .sbt settings 也会被添加到 .scala settings 当中
  35. 默认情况下 .sbt 中的 settings 会被纳入 Project 级别的 Scope 中,除非明确指定哪些Settings定义的Scope .scala中则可以将settings纳入Build级别的Scope,也可以纳入Project级别的Scope
  36. 2) *.sbt
  37. a) *.sbt 项目根目录下
  38. b) .sbt 中定义常用的 settings
  39. 3) *.scala
  40. a) *.scala 项目根目录下的 project 目录下
  41. b) 在多模块项目构建中,为了避免多个 .sbt 的存在引入过多的繁琐,才会只用.scala形式的build定义。
  42. 4) sbt 目录结构 (可以一层嵌套一层)
  43. 从第一层的项目根目录开始, 其下project/目录内部再嵌套project/目录,可以无限递归
  44. hello/
  45. *.scala
  46. build.sbt
  47. project/
  48. build.properties : 声明使用的要使用哪个版本的SBT来编译当前项目
  49. plugins.sbt : 声明当前项目希望使用哪些插件来增强当前项目使用的sbt的功能
  50. *.scala
  51. build.sbt
  52. /project
  53. *.scala
  54. src/main/resources : 配置文件资料目录
  55. src/main/java : java 代码
  56. src/main/scala : scala 代码目录
  57. lib_managed : 工程所依赖的 jar 文件。会在sbt更新的时候添加到该目录

2.1 build.sbt 实际案例配置

  1. import AssemblyKeys._
  2. // 打开 assembly 插件功能
  3. assemblySettings
  4. // 配置 assembly 插件所有使用的 JAR
  5. jarName in assembly := "recommend-2.0.jar"
  6. // 项目名称
  7. name := "recommend-2.0"
  8. // 组织名称
  9. organization := "com.angejia.dw.recommend"
  10. // 项目版本号
  11. version := "2.0"
  12. // scala 版本
  13. scalaVersion := "2.10.6"
  14. // Eclipse 支持
  15. EclipseKeys.createSrc := EclipseCreateSrc.Default + EclipseCreateSrc.Resource
  16. // 非托管资源目录
  17. unmanagedResourceDirectories in Compile += { baseDirectory.value / "src/main/resources" }
  18. // 非托管依赖(项目根目录 lib)
  19. unmanagedBase := baseDirectory.value / "lib"
  20. // 相关依赖
  21. // provided 关键字, 不会把 provided 关键字的依赖,打入到 jar 中.
  22. libraryDependencies ++= Seq(
  23. // scala-library
  24. "org.scala-lang" % "scala-library" % "2.10.6",
  25. // hadoop 依赖
  26. "org.apache.hadoop" % "hadoop-common" % "2.6.0",
  27. "org.apache.hadoop" % "hadoop-hdfs" % "2.6.0",
  28. "org.apache.hadoop" % "hadoop-client" % "2.6.0",
  29. // Spark 依赖 : spark-core_2.10(spark 所属 scala 版本号) 1.5.2(spark 版本号)
  30. "org.apache.spark" % "spark-core_2.10" % "1.5.2",
  31. "org.apache.spark" % "spark-streaming_2.10" % "1.5.2",
  32. "org.apache.spark" % "spark-streaming-kafka_2.10" % "1.5.2"
  33. exclude("org.apache.avro","*")
  34. exclude("org.slf4j","*"),
  35. "org.apache.spark" % "spark-mllib_2.10" % "1.5.2",
  36. //"org.apache.avro" % "avro" % "1.7.4",
  37. //"org.apache.avro" % "avro-ipc" % "1.7.4" excludeAll(excludeNetty),
  38. // jblas 线性代数库,求向量点积
  39. "org.jblas" % "jblas" % "1.2.4",
  40. // Kafka 依赖
  41. "org.apache.kafka" % "kafka_2.10" % "0.9.0.0" ,
  42. "org.apache.kafka" % "kafka-log4j-appender" % "0.9.0.0" % "provided" ,
  43. "org.apache.kafka" % "kafka_2.10" % "0.9.0.0"
  44. exclude("javax.jms", "jms")
  45. exclude("com.sun.jdmk", "jmxtools")
  46. exclude("com.sun.jmx", "jmxri"),
  47. // Hbase 依赖
  48. //"org.apache.hbase" % "hbase" % "1.0.0",
  49. "org.apache.hbase" % "hbase-common" % "1.0.0",
  50. "org.apache.hbase" % "hbase-client" % "1.0.0",
  51. "org.apache.hbase" % "hbase-server" % "1.0.0",
  52. // Mysql 依赖
  53. "mysql" % "mysql-connector-java" % "5.1.38",
  54. // play Json 包, 版本太高会冲突
  55. "com.typesafe.play" % "play-json_2.10" % "2.3.9",
  56. // spray Json 包
  57. "io.spray" % "spray-json_2.10" % "1.3.2",
  58. // smart Json 包
  59. "net.minidev" % "json-smart" % "2.2.1",
  60. // java Json 包
  61. "com.googlecode.json-simple" % "json-simple" % "1.1.1",
  62. "net.sf.jopt-simple" % "jopt-simple" % "4.9" % "provided",
  63. "joda-time" % "joda-time" % "2.9.2" % "provided",
  64. "log4j" % "log4j" % "1.2.9"
  65. )
  66. // 强制默认合并
  67. mergeStrategy in assembly <<= (mergeStrategy in assembly) { mergeStrategy => {
  68. case entry => {
  69. val strategy = mergeStrategy(entry)
  70. if (strategy == MergeStrategy.deduplicate) MergeStrategy.first
  71. else strategy
  72. }
  73. }}
  74. // 配置远程资源
  75. resolvers ++= Seq(
  76. // HTTPS is unavailable for Maven Central
  77. "Maven Repository" at "http://repo.maven.apache.org/maven2",
  78. "Apache Repository" at "https://repository.apache.org/content/repositories/releases",
  79. "JBoss Repository" at "https://repository.jboss.org/nexus/content/repositories/releases/",
  80. "MQTT Repository" at "https://repo.eclipse.org/content/repositories/paho-releases/",
  81. "Cloudera Repository" at "https://repository.cloudera.com/artifactory/cloudera-repos/",
  82. "Elaticsearch Repository" at "https://mvnrepository.com/artifact/org.elasticsearch/elasticsearch",
  83. // For Sonatype publishing
  84. // "sonatype-snapshots" at "https://oss.sonatype.org/content/repositories/snapshots",
  85. // "sonatype-staging" at "https://oss.sonatype.org/service/local/staging/deploy/maven2/",
  86. // also check the local Maven repository ~/.m2
  87. //本地 mavan 仓库地址,详细目录写自己的
  88. "Local Maven Repository" at "file:///usr/local/maven/repository",
  89. Resolver.mavenLocal
  90. )
  91. // 配置本地资源
  92. // resolvers += "Local Maven Repository" at "file:///usr/local/maven/repository"
  93. // 指定 JDK 版本
  94. javaHome := Some(file("/opt/jdk/jdk1.7.0"))

2.2 assembly 打包 jar 冲突解决方案

对于 jar 冲突具体有几个解决方案

  • 排除冲突的 package
  • 合并冲突的 class
  • 排除冲突的 jars
  1. 1. provided 关键字, 不把这个依赖包打入 jar
  2. 1: 不加入打包法
  3. "org.apache.kafka" % "kafka-log4j-appender" % "0.9.0.0" % "provided"
  4. 2. excludeAll 排除冲突
  5. 1: 排除组织和包名法
  6. "org.apache.hadoop" % "hadoop-client" % "2.6.0" excludeAll(
  7. // 排除名为 hive-metastore 的包
  8. ExclusionRule(name = "hive-metastore"),
  9. // 排除组织名为 com.sun.jdmk 的包
  10. ExclusionRule(organization = "com.sun.jdmk")
  11. )
  12. 3. mergeStrategy 合并策略, class、文件做合并策略
  13. 1: 对每个文件都有合并策略
  14. mergeStrategy in assembly <<= (mergeStrategy in assembly) { (old) => {
  15. case PathList("org", "slf4j", xs@_*) => MergeStrategy.last
  16. // 排除 指定 class
  17. case PathList(ps @ _*) if ps.last endsWith "ILoggerFactory.class" => MergeStrategy.first
  18. case PathList(ps@_*) if ps.last endsWith "pom.properties" => MergeStrategy.last
  19. case PathList(ps@_*) if ps.last endsWith ".class" => MergeStrategy.last
  20. case PathList(ps@_*) if ps.last endsWith ".thrift" => MergeStrategy.last
  21. case PathList(ps@_*) if ps.last endsWith ".xml" => MergeStrategy.last
  22. case PathList(ps@_*) if ps.last endsWith ".css" => MergeStrategy.last
  23. case PathList(ps@_*) if ps.last endsWith ".properties" => MergeStrategy.last
  24. case PathList("javax", "servlet", xs @ _*) => MergeStrategy.last
  25. case x => old(x)
  26. }
  27. }
  28. 2: 强制合并策略, 对所有冲突使用一个合并策略
  29. mergeStrategy in assembly <<= (mergeStrategy in assembly) { mergeStrategy => {
  30. case entry => {
  31. val strategy = mergeStrategy(entry)
  32. if (strategy == MergeStrategy.deduplicate) MergeStrategy.first
  33. else strategy
  34. }
  35. }
  36. }
  37. 4. 强制排除 jars 不打入依赖包
  38. 1: 排除指定 jar, excludedJars(sbt 0.13 或者之前版本)
  39. excludedJars in assembly <<= (fullClasspath in assembly) map { cp =>
  40. cp filter {_.data.getName == "hive-metastore-1.1.0.jar"}
  41. }
  42. 2: 排除指定 jar, assemblyExcludedJars(sbt 0.13 之后版本, 详细见 github 文档):
  43. // 官方写法
  44. assemblyExcludedJars in assembly := {
  45. val cp = (fullClasspath in assembly).value
  46. cp filter {_.data.getName == "compile-0.1.0.jar"}
  47. }
  48. // 自定义写法
  49. assemblyExcludedJars in assembly := {
  50. val cp = (fullClasspath in assembly).value
  51. cp filter { f =>
  52. f.data.getName.contains("spark-core") ||
  53. f.data.getName == "spark-core_2.11-2.0.1.jar"
  54. }
  55. }

3. project/plugins.sbt 插件配置文件

  1. // 配置远程资源
  2. resolvers += Resolver.url("artifactory", url("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases"))(Resolver.ivyStylePatterns)
  3. resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"
  4. // eclipse 插件
  5. addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.5.0")
  6. // 打包所有依赖的插件
  7. addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.11.2")
  8. // 依赖树 插件 dependencyTree, dependencyBrowseGraph
  9. addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.2")

4. 运行项目

4.1 运行模式和组件

  1. 1. SBT 支持两种使用方式:
  2. 1) 批处理模式(batch mode)
  3. sbt compile test package 批处理模式 (命令前后有依赖关系)
  4. 2) 可交互模式(interactive mode)
  5. sbt
  6. > compile
  7. > test
  8. > package
  9. 2. SBT 阶段
  10. 1) 阶段
  11. compile 编译
  12. test-compile 测试编译
  13. test 测试用例
  14. run 运行
  15. package 打包
  16. 3. 触发器 ~
  17. sbt ~compile 当源码变动时,自动编译
  18. sbt ~run 变动时,运行

4.2 实际案例

  1. 1. 创建项目结构
  2. mkdir sbt-app
  3. cd sbt-app
  4. mkdir project
  5. 2. *. sbt 文件配置
  6. # 项目说明
  7. vim build.sbt
  8. build.sbt
  9. # 添加插件
  10. vim project/plugins.sbt
  11. project/plugins.sbt
  12. 4. 运行
  13. sbt clean compile // 先清除target目录下的所有的文件,再编译
  14. sbt eclipse // 将当前的sbt项目转为eclipse项目
  15. sbt update // 更新项目依赖
  16. sbt run // 运行当前项目(需要设置:mainClass
  17. sbt test // 运行测试用例
  18. sbt clean compile package // 组合命令
  19. sbt reload eclipse // 更新项目依赖, 如果在 eclipse 要切换到 Scala 环境中, 重新 clean 项目
  20. sbt update eclipse
  21. # 测试程序
  22. echo 'object HelloWorld { def main(args: Array[String]) = println("HelloWorld") }' >> src/main/scala/HelloWorld.scala
  23. # sbt 打包 jar
  24. sbt clean assembly 打包所有依赖 jar
  25. java -cp target/scala-2.10/xx.xxx.xx-SNAPSHOT.jar HelloWorld
  26. sbt 命令合集
  27. console - 启用 Scala 解释器
  28. actions 显示对当前工程可用的命令
  29. update 下载依赖
  30. compile 编译代码
  31. test 运行测试代码
  32. run - 运行代码
  33. package 创建一个可发布的jar
  34. publish-local 把构建出来的jar包安装到本地的ivy缓存
  35. publish jar包发布到远程仓库(如果配置了的话)
  36. test-failed 运行失败的spec
  37. test-quick 运行所有失败的以及/或者是由依赖更新的spec
  38. sbt clean compile "testOnly TestA TestB" : testOnly 有两个参数 TestA TestB。这个命令会按顺序执行(clean compile 然后 testOnly
  39. 5. 查看依赖树
  40. sbt dependency-graph