首页 > 解决方案 > sbt run 作为一个子模块运行

问题描述

我想知道我是否可以在开发中将 Play 作为子模块运行?这是项目结构:

根目录下只有一个build.sbt文件,它指定了项目的结构。

以前,我将 Play 模块作为一个单独的项目,它有自己的build.sbt,我可以简单地在开发模式下运行它sbt run

但是,在我将 Play 模块与其他模块合并为一个项目后,sbt "project projectName" run仍然可以在开发模式下启动 Play 模块,但是当我尝试点击任何端点时,我得到了注入错误,例如No implementation for models.services.UserService was bound.

这里是一部分build.sbtemberconflagration是 Play 项目。

lazy val root = project
  .in(file("."))
  .aggregate(embercore)
  .aggregate(emberdataset)
  .aggregate(emberconflagration)
  .aggregate(emberservice)
  .aggregate(embersession)
  .aggregate(emberetl)
  .aggregate(embermodel)
  .aggregate(emberclient)
  .aggregate(emberserver)
  .aggregate(emberservermongo)
  .aggregate(emberstreaming)
  .settings(commonSettings: _*)
  .settings(name := "ember-conflagration-root")

lazy val embercore = (project in file("./embercore"))
  .settings(commonSettings: _*)
  .settings(testSettings: _*)
  .settings(
    name := "embercore",
    libraryDependencies ++= Seq(
      Libraries.scalatest,
      Libraries.play_json
    ),
    resolvers ++= Seq(
      "Apache Repository" at "https://repository.apache.org/content/repositories/releases/",
      "Cloudera Repository" at "https://repository.cloudera.com/artifactory/cloudera-repos/",
      Resolver.sonatypeRepo("public")
    ),
    javaOptions in assembly += "-xmx6g"
  )

lazy val emberservice = (project in file("./emberservice"))
  .settings(commonSettings: _*)
  .settings(testSettings: _*)
  .settings(
    name := "emberservice",
    libraryDependencies ++= Seq(
      Libraries.scalatest,
      Libraries.play_json,
      Libraries.scala_j
    ),
    resolvers ++= Seq(
      "Apache Repository" at "https://repository.apache.org/content/repositories/releases/",
      "Cloudera Repository" at "https://repository.cloudera.com/artifactory/cloudera-repos/",
      Resolver.sonatypeRepo("public")
    ),
    javaOptions in assembly += "-xmx6g"
  )
  .dependsOn(embercore)

lazy val emberdataset = (project in file("./emberdataset"))
  .settings(commonSettings: _*)
  .settings(testSettings: _*)
  .settings(
    name := "emberdataset",
    libraryDependencies ++= Seq(
      Libraries.scalatest,
      Libraries.spark_core_conflP,
      Libraries.spark_mllib_conflP,
      Libraries.spark_sql_conflP,
      Libraries.mysql_connector,
      Libraries.spark_xml
    ),
    resolvers ++= Seq(
      "Apache Repository" at "https://repository.apache.org/content/repositories/releases/",
      "Cloudera Repository" at "https://repository.cloudera.com/artifactory/cloudera-repos/",
      Resolver.sonatypeRepo("public")
    ),
    javaOptions in assembly += "-xmx6g"
  )
  .dependsOn(embercore)

lazy val embersession = (project in file("./embersession"))
  .enablePlugins(LauncherJarPlugin)
  .settings(commonSettings: _*)
  .settings(testSettings: _*)
  .settings(
    name := "embersession",
    libraryDependencies ++= Seq(
      Libraries.scalatest,
      Libraries.h2o_sparkling_water_core
      exclude ("com.fasterxml.jackson.core", "jackson-core")
      exclude ("com.fasterxml.jackson.core", "jackson-databind")
      exclude ("javax.servlet", "servlet-api"),
      // exclude ("org.apache.spark", "spark-sql_2.11")   // Comment out for standard build. Uncomment for EmberSession assembly.
      // exclude ("org.apache.spark", "spark-core_2.11")  // Comment out for standard build. Uncomment for EmberSession assembly.
      // exclude ("org.apache.spark", "spark-mllib_2.11") // Comment out for standard build. Uncomment for EmberSession assembly.
      // exclude ("org.apache.hadoop", "hadoop-common"),  // Comment out for standard build. Uncomment for EmberSession assembly.
      Libraries.jackson_scala,
      Libraries.duke,
      Libraries.scala_library,
      Libraries.spark_core_conflP,
      Libraries.spark_mllib_conflP,
      Libraries.spark_sql_conflP
    ),

    mainClass in assembly := Some("com.metistream.ember.embersession.Test"),
    javaOptions in assembly += "-xmx6g",
    resolvers ++= Seq(
      "Apache Repository" at "https://repository.apache.org/content/repositories/releases/",
      "Cloudera Repository" at "https://repository.cloudera.com/artifactory/cloudera-repos/",
      Resolver.sonatypeRepo("public")
    ),
    assemblyShadeRules in assembly ++= Seq(
      ShadeRule.rename("com.esotericsoftware.kryo.**" -> "emberkryo.@1").inAll,
      ShadeRule.rename("com.fasterxml.jackson.**" -> "emberjackson.@1").inAll,
      ShadeRule.rename("play.api.**" -> "emberplay.play.api.@1").inAll
    ),
    assemblyMergeStrategy in assembly := {
      case PathList("META-INF", "services", "org.apache.hadoop.fs.FileSystem") => MergeStrategy.filterDistinctLines
      case PathList("reference.conf")                                          => MergeStrategy.concat
      case PathList("META-INF", xs @ _*)                                       => MergeStrategy.discard
      case x                                                                   => MergeStrategy.first
    }
  )
  .dependsOn(embercore, emberdataset, emberservice)

lazy val emberconflagration = (project in file("security-layer"))
  .enablePlugins(PlayScala)
  .settings(commonSettings: _*)
  .settings(testSettings: _*)
  .settings(
    name := "ember-conflagration",
    libraryDependencies ++= Seq(
      jdbc,
      cache,
      ws,
      filters,
      Libraries.play2_reactivemongo,
      Libraries.mockito,
      Libraries.embed_mongo,
      Libraries.play_silhouette,
      Libraries.silhouette_password,
      Libraries.silhouette_persistence,
      Libraries.silhouette_crypto,
      Libraries.silhouette_testkit,
      Libraries.scala_guice,
      Libraries.ficus,
      Libraries.mleap_runtime,
      Libraries.google_api_dataproc,
      Libraries.scalaj_http,
      Libraries.google_core,
      Libraries.google_client,
      Libraries.google_sqladmin,
      Libraries.google_cloud_compute,
      Libraries.google_api_services,
      Libraries.google_cloud_storage,
      Libraries.postgresql_connector,
      Libraries.jersey_media_glass,
      Libraries.jersey_core_glass,
      Libraries.jackson_xml,
      Libraries.jackson_scala,
      Libraries.janino,
      Libraries.play_json_extensions,
      Libraries.hapi_base,
      Libraries.hapi_structures_v21,
      Libraries.hapi_structures_v22,
      Libraries.hapi_structures_v23,
      Libraries.hapi_structures_v231,
      Libraries.hapi_structures_v24,
      Libraries.hapi_structures_v25,
      Libraries.hapi_structures_v251,
      Libraries.hapi_structures_v26,
      Libraries.play_quartz_extension,
      Libraries.elastic4s_core,
      Libraries.elastic4s_http,
      Libraries.scalatest,
      specs2 % Test,
      Libraries.uimaj_core,
      Libraries.spark_core_confl,
      Libraries.spark_mllib_confl,
      Libraries.spark_sql_confl,
      Libraries.unbound_id,
      Libraries.swagger
    ),
    coverageExcludedPackages := "<empty>;Reverse.*;router\\..*",
    // Assembly Settings
    assemblyShadeRules in assembly ++= Seq(
      ShadeRule
        .rename("com.google.common.**" -> "my_guava.@1")
        .inLibrary("com.google.api-client" % "google-api-client" % "1.22.0")
    ),
    mainClass in assembly := Some("play.core.server.ProdServerStart"),
    fullClasspath in assembly += Attributed.blank(PlayKeys.playPackageAssets.value),
    assemblyMergeStrategy in assembly := {
      case PathList("META-INF", "MANIFEST.MF") => MergeStrategy.discard
      case PathList("META-INF", xs @ _*)       => MergeStrategy.first
      case x                                   => MergeStrategy.first
    },
    projectDependencies := {
      Seq(
        (projectID in emberdataset).value.excludeAll(ExclusionRule(organization = "org.slf4j"),
                                                     ExclusionRule(organization = "io.netty"))
      )
    },

    fork in run := false,
    resolvers ++= Seq(
      "elasticsearch-releases" at "https://artifacts.elastic.co/maven",
      "sonatype snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/",
      Resolver.bintrayRepo("iheartradio", "maven"),
      "Atlassian Releases" at "https://maven.atlassian.com/public/",
      Resolver.url("Typesafe Ivy releases", url("https://repo.typesafe.com/typesafe/ivy-releases"))(
        Resolver.ivyStylePatterns)
    ),
    javaOptions in assembly += "-xmx6g"
  )
  .dependsOn(embercore, emberdataset, emberetl)

标签: scalaplayframeworksbt

解决方案


我认为这只是您的特定应用程序不起作用。这可能是因为您有多个相互碰撞的包。这是一个有效的例子。

目录结构

./build.sbt
./mod1
./mod1/src
./mod1/src/main
./mod1/src/main/scala
./mod1/src/main/scala/Hello.scala
./mod2
./mod2/app
./mod2/app/controllers
./mod2/app/controllers/HomeController.scala
./mod2/app/modules/MainModule.scala
./mod2/conf
./mod2/conf/application.conf
./mod2/conf/logback.xml
./mod2/conf/messages
./mod2/conf/routes
./mod3
./mod3/src
./mod3/src/main
./mod3/src/main/scala
./mod3/src/main/scala/Hello.scala
./project/plugins.sbt

重要文件:

构建.sbt

name := """root"""
organization := "com.example"

version := "1.0-SNAPSHOT"
lazy val mod1 = project in file("mod1")
lazy val mod2 = (project in file("mod2"))
  .enablePlugins(PlayScala)
  .settings(
    name := """myplayproject""",
    organization := "com.example",
    version := "1.0-SNAPSHOT",
    scalaVersion := "2.12.6",
    libraryDependencies += guice,
    libraryDependencies += "org.scalatestplus.play" %% "scalatestplus-play" % "3.1.2" % Test
    )

lazy val mod3 = project in file("mod3")
lazy val root = (project in file("."))
  .aggregate(mod1)
  .aggregate(mod2)
  .aggregate(mod3)

HomeController.scala

package controllers

import javax.inject._
import play.api._
import play.api.mvc._

trait MyServiceLike {
  def getString: String
}

class MyService extends MyServiceLike {
  override def getString: String = "hello"
}

@Singleton
class HomeController @Inject()(cc: ControllerComponents, myService: MyServiceLike) extends AbstractController(cc) {
  def index() = Action { implicit request: Request[AnyContent] =>
    Ok(myService.getString)
  }
}

项目/plugins.sbt

addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.16")

mod2/conf/application.conf

play.modules.enabled += "modules.MainModule"

mod2/app/modules/MainModule.scala

package modules

import controllers.MyService
import controllers.MyServiceLike
import play.api.Configuration
import play.api.Environment
import play.api.inject.Binding
import play.api.inject.Module

class MainModule extends Module {
  override def bindings(environment: Environment, configuration: Configuration): Seq[Binding[_]] = Seq(
    bind[MyServiceLike].to[MyService]
  )
}

然后,您可以通过启动运行sbt

project mod2
run

推荐阅读