IntelliJ中客户端项目访问Akka Actor的依赖配置与结构问题
Great question! When building a client to talk to your Akka Actor server while reusing those message classes, the critical move is to split your shared code into a common module—this way both server and client can pull in the same definitions without duplication. Let’s walk through how to structure this and set up dependencies properly:
The goal is to separate concerns so shared code lives in its own module, while server and client handle their specific logic. Here’s a clean, scalable structure:
your-root-project/ ├── build.sbt ├── core/ │ ├── src/ │ │ └── main/ │ │ └── scala/ │ │ └── com/yourcompany/ │ │ └── messages/ │ │ ├── Greet.scala │ │ ├── GreetResponse.scala │ │ └── SharedSerializers.scala │ └── build.sbt ├── akka-server/ │ ├── src/ │ │ └── main/ │ │ ├── scala/ │ │ │ └── com/yourcompany/ │ │ │ ├── actors/ │ │ │ │ └── GreeterActor.scala │ │ │ └── ServerApp.scala │ │ └── resources/ │ │ └── application.conf │ └── build.sbt └── akka-client/ ├── src/ │ └── main/ │ ├── scala/ │ │ └── com/yourcompany/ │ │ └── ClientApp.scala │ └── resources/ │ └── application.conf └── build.sbt
- Core Module: This holds all shared code—your message case classes, serialization helpers, and any common constants. Keep it lightweight, no unnecessary Akka dependencies beyond what’s needed for serialization.
- Akka Server Module: Your existing Actor project, now depending on the core module. It contains your Actor implementations, server startup logic, and business rules.
- Akka Client Module: A standalone project that pulls in the core module and Akka Remote (or Akka HTTP if you prefer REST) to send messages to the server.
Core Module (core/build.sbt)
You’ll need Akka serialization utilities here since messages need to be serialized for network transport:
name := "core" version := "1.0.0" scalaVersion := "2.13.12" // Match your project's Scala version libraryDependencies ++= Seq( "com.typesafe.akka" %% "akka-actor-typed" % "2.8.5", // Use untyped akka-actor if you're not using typed Actors "com.typesafe.akka" %% "akka-serialization-jackson" % "2.8.5" // Jackson for JSON serialization (Protobuf is another great option) )
Akka Server Module (akka-server/build.sbt)
Depend on the core module and add Akka Remote for network communication:
name := "akka-server" version := "1.0.0" scalaVersion := "2.13.12" // Reference the core module lazy val core = project.in(file("../core")) libraryDependencies ++= Seq( "com.typesafe.akka" %% "akka-actor-typed" % "2.8.5", "com.typesafe.akka" %% "akka-remote" % "2.8.5", "com.typesafe.akka" %% "akka-serialization-jackson" % "2.8.5" ) // Pull in the core module's code dependsOn(core)
Akka Client Module (akka-client/build.sbt)
Same logic as the server—depend on core and add Akka Remote:
name := "akka-client" version := "1.0.0" scalaVersion := "2.13.12" lazy val core = project.in(file("../core")) libraryDependencies ++= Seq( "com.typesafe.akka" %% "akka-actor-typed" % "2.8.5", "com.typesafe.akka" %% "akka-remote" % "2.8.5", "com.typesafe.akka" %% "akka-serialization-jackson" % "2.8.5" ) dependsOn(core)
- Serialization Setup: Ensure your message case classes are properly configured for serialization. For Jackson, Akka handles most case classes automatically, but you can add annotations if needed. For example:
package com.yourcompany.messages case class Greet(name: String, replyTo: akka.actor.typed.ActorRef[GreetResponse]) case class GreetResponse(message: String) - Remote Configuration: Both server and client need
application.confsettings to enable remote communication. Example server config:akka { actor { provider = remote serialization-bindings { "com.yourcompany.messages.Greet" = jackson-json "com.yourcompany.messages.GreetResponse" = jackson-json } } remote { artery { enabled = true transport = tcp canonical.hostname = "127.0.0.1" canonical.port = 2552 } } } - Client Actor Resolution: The client needs to locate the server’s Actor using its remote address. For typed Actors, here’s a quick example:
import akka.actor.typed.ActorSystem import akka.actor.typed.scaladsl.AskPattern._ import akka.util.Timeout import com.yourcompany.messages._ import scala.concurrent.duration._ object ClientApp extends App { implicit val system: ActorSystem[Nothing] = ActorSystem[Nothing]((), "client-system") implicit val timeout: Timeout = 5.seconds // Resolve the remote Greeter Actor val greeterActor = system.systemActorSelection("akka://server-system@127.0.0.1:2552/user/greeter") // Send a message and handle the response val response = greeterActor.ask[GreetResponse](ref => Greet("Alice", ref)) response.onComplete { case Right(resp) => println(s"Server said: ${resp.message}") case Left(ex) => println(s"Oops, error: ${ex.getMessage}") } }
If you don’t want to use Akka Remote directly, you can expose an HTTP endpoint from the server (using Akka HTTP) and have the client send JSON requests. The core module still holds the message classes—you’ll just serialize/deserialize them to JSON for HTTP communication instead of using Akka’s remote serialization.
内容的提问来源于stack exchange,提问作者Mandroid

