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

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)

原因分析

  1. 配置合并策略缺失:sbt-assembly合并策略设置为case _ => MergeStrategy.first,导致多个依赖中的reference.conf仅保留第一个,丢失了Akka Stream模块默认的akka.stream.materializer.dispatcher配置项。
  2. 显式配置未定义:自定义application.conf中未配置akka.stream.materializer.dispatcher,打包后Jar中缺少Akka默认配置,导致ActorMaterializerSettings初始化时找不到该键。
  3. 代码冗余操作:手动创建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)

验证步骤

  1. 选择任意一种方案修改代码或配置。
  2. 重新执行sbt assembly打包。
  3. 运行打包后的Jar文件,确认启动正常且API可访问。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 15:35:56