Scala Akka HTTP打包Jar后启动报错:找不到'dispatcher'配置项
Akka HTTP打包Jar后启动报ConfigException$Missing问题排查与解决
问题描述
使用Scala 2.11.12结合Akka HTTP开发API,IDE中运行正常,但打包成Jar文件后启动失败,抛出com.typesafe.config.ConfigException$Missing异常,提示No configuration setting found for key 'dispatcher'。相关配置、代码及错误日志如下:
build.sbt配置
ThisBuild / version := "0.1.0-SNAPSHOT" ThisBuild / scalaVersion := "2.11.12" lazy val root = (project in file(".")) .settings( name := "JNPM_SCALA_DATA_API", idePackagePrefix := Some("org.jio.jnpm"), resolvers += "Typesafe Repo" at "https://repo.typesafe.com/typesafe/releases/", libraryDependencies ++= Seq( "com.typesafe.akka" %% "akka-http" % "10.0.15", "com.typesafe.akka" %% "akka-actor" % "2.4.20", "com.typesafe.akka" %% "akka-stream" % "2.4.20", "com.typesafe.akka" %% "akka-http-spray-json" % "10.0.15" ), assembly / assemblyMergeStrategy := { case PathList("META-INF", xs @ _*) => MergeStrategy.discard case "application.conf" => MergeStrategy.concat case _ => MergeStrategy.first } )
application.conf配置
akka { loglevel = "INFO" actor { default-dispatcher { type = "Dispatcher" executor = "fork-join-executor" fork-join-executor { parallelism-min = 2 parallelism-factor = 2.0 parallelism-max = 10 } } } stream { materializer { initial-input-buffer-size = 16 max-input-buffer-size = 128 } } }
主类代码
import akka.actor.ActorSystem import akka.stream.ActorMaterializer import akka.http.scaladsl.Http import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.model.{HttpResponse, StatusCodes} import akka.http.scaladsl.model.StatusCodes._ import akka.http.scaladsl.server.Route import models.{JsonSupport, ReportPayload} import scala.concurrent.ExecutionContextExecutor import akka.stream.ActorMaterializerSettings import com.typesafe.config.ConfigFactory object WebServer extends JsonSupport{ def main(args: Array[String]): Unit = { implicit val system: ActorSystem = ActorSystem("akkaHttpServer", ConfigFactory.load()) println("Dispatcher Config: " + system.settings.config.getConfig("akka.actor.default-dispatcher")) val materializerSettings = ActorMaterializerSettings(system).withDispatcher("akka.actor.default-dispatcher") implicit val materializer: ActorMaterializer = ActorMaterializer(materializerSettings)(system) implicit val executionContext: ExecutionContextExecutor = system.dispatcher val route: Route = concat( get { path("hello") { complete(HttpResponse(OK, entity = "Hello from Akka HTTP!")) } }, post { path("echo") { entity(as[String]) { body => complete(HttpResponse(OK, entity = body)) } } }, post { path("jnpm" / "pm" / "data" / "network_element") { entity(as[ReportPayload]) { reportPayload => println(s"Received report for user: ${reportPayload.user_id}") complete(StatusCodes.OK, s"Report for ${reportPayload.report_name} received and is being processed.") } } } ) val bindingFuture = Http().bindAndHandle(route, "0.0.0.0", 8088) println(s"Server online at http://localhost:8080/\nPress RETURN to stop...") scala.io.StdIn.readLine() bindingFuture .flatMap(_.unbind()) .onComplete(_ => system.terminate()) } }
错误日志
Loading config from properties {java.runtime.name=Java(TM) SE Runtime Environment, ...} Loading config from resource 'application.conf' URL jar:file:/C:/SCALA_SPARK/JNPM_SCALA_DATA_API/target/scala-2.11/JNPM_SCALA_DATA_API-assembly-0.1.0-SNAPSHOT.jar!/application.conf from class loader sun.misc.Launcher$AppClassLoader@647e05 ... Dispatcher Config: Config(SimpleConfigObject({"executor":"fork-join-executor","fork-join-executor":{"parallelism-factor":2,"parallelism-max":10,"parallelism-min":2},"type":"Dispatcher"})) Exception in thread "main" com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'dispatcher' at com.typesafe.config.impl.SimpleConfig.findKeyOrNull(SimpleConfig.java:152) at com.typesafe.config.impl.SimpleConfig.findOrNull(SimpleConfig.java:170) at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:184) at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:189) at com.typesafe.config.impl.SimpleConfig.getString(SimpleConfig.java:246) at akka.stream.ActorMaterializerSettings$.apply(ActorMaterializer.scala:267) at akka.stream.ActorMaterializerSettings$.apply(ActorMaterializer.scala:258) at org.jio.jnpm.WebServer$.main(WebServer.scala:31) at org.jio.jnpm.WebServer.main(WebServer.scala)
原因分析
- 配置合并策略缺失:sbt-assembly合并策略设置为
case _ => MergeStrategy.first,导致多个依赖中的reference.conf仅保留第一个,丢失了Akka Stream模块默认的akka.stream.materializer.dispatcher配置项。 - 显式配置未定义:自定义
application.conf中未配置akka.stream.materializer.dispatcher,打包后Jar中缺少Akka默认配置,导致ActorMaterializerSettings初始化时找不到该键。 - 代码冗余操作:手动创建
ActorMaterializerSettings并指定调度器属于冗余操作,默认情况下Akka会自动使用akka.actor.default-dispatcher作为流materializer的调度器。
解决方案
方案一:修复sbt-assembly配置合并策略
修改build.sbt中的assemblyMergeStrategy,添加reference.conf合并规则,确保所有依赖的默认配置被正确合并:
assembly / assemblyMergeStrategy := { case PathList("META-INF", xs @ _*) => MergeStrategy.discard case "application.conf" => MergeStrategy.concat case "reference.conf" => MergeStrategy.concat // 新增:合并所有依赖的reference.conf case _ => MergeStrategy.first }
方案二:在application.conf中显式添加缺失配置
在akka.stream.materializer节点下添加dispatcher配置,直接指定使用默认调度器:
akka { loglevel = "INFO" actor { default-dispatcher { type = "Dispatcher" executor = "fork-join-executor" fork-join-executor { parallelism-min = 2 parallelism-factor = 2.0 parallelism-max = 10 } } } stream { materializer { initial-input-buffer-size = 16 max-input-buffer-size = 128 dispatcher = "akka.actor.default-dispatcher" // 新增:显式指定调度器 } } }
方案三:简化代码,使用默认ActorMaterializer
删除手动创建ActorMaterializerSettings的代码,直接使用默认初始化方式,避免读取缺失的配置项:
// 替换原有的materializer初始化代码 implicit val materializer: ActorMaterializer = ActorMaterializer()(system)
验证步骤
- 选择任意一种方案修改代码或配置。
- 重新执行
sbt assembly打包。 - 运行打包后的Jar文件,确认启动正常且API可访问。
内容的提问来源于stack exchange,提问作者vivekdesai
相关产品推荐
相关产品推荐

