Akka Http如何拆分需要implicit ActorSystem的路由到不同文件
路由拆分依赖隐式ActorSystem的实现方案
你现有代码无法运行的核心原因是:用单例object定义的路由会在类加载阶段就完成route字段的初始化,此时MyApp中声明的ActorSystem还未创建,自然找不到所需的隐式实例导致报错。
常用的实现方案有以下两种,按需选择即可:
方案1:类构造函数传入(最推荐,易测试)
将单例object改为class,把需要的隐式参数放到第二个参数列表中,初始化时会自动从上下文传入隐式实例:
// UserRoutes.scala class UserRoutes()(implicit val system: ActorSystem[Nothing], ec: ExecutionContext) { // 路由逻辑可直接使用构造函数传入的隐式实例发起HTTP请求 val route: Route = ??? } // OrderRoutes.scala 写法和UserRoutes一致 class OrderRoutes()(implicit val system: ActorSystem[Nothing], ec: ExecutionContext) { val route: Route = ??? } // MyApp.scala object MyApp extends App { implicit val system = ActorSystem(Behaviors.empty, "my-system") implicit val ec = system.executionContext // 隐式参数会自动注入,无需手动传参 val allRoutes = new UserRoutes().route ~ new OrderRoutes().route Http().newServerAt("localhost", 8888).bind(allRoutes) }
该方案耦合度最低,单元测试时可以随意传入测试用的ActorSystem实例,适合绝大多数生产场景。
如果路由逻辑非常简单,也可以简化为给route方法加隐式参数,不用修改为类:
object UserRoutes { def route(implicit system: ActorSystem[Nothing], ec: ExecutionContext): Route = ??? } // 调用时直接写UserRoutes.route即可,隐式实例会自动从上下文传入
方案2:trait混入实现(适合路由需要灵活组合的场景)
用trait定义路由,声明抽象的system字段,在启动类中统一实现该字段即可:
// 路由定义文件 trait UserRoutes { // 声明需要子类实现的ActorSystem implicit def system: ActorSystem[Nothing] implicit lazy val ec: ExecutionContext = system.executionContext val userRoute: Route = ??? } trait OrderRoutes { implicit def system: ActorSystem[Nothing] implicit lazy val ec: ExecutionContext = system.executionContext val orderRoute: Route = ??? } // 启动类 object MyApp extends App with UserRoutes with OrderRoutes { // 实现trait中声明的抽象字段 override implicit val system = ActorSystem(Behaviors.empty, "my-system") val allRoutes = userRoute ~ orderRoute Http().newServerAt("localhost", 8888).bind(allRoutes) }
该方案不用实例化多个路由类,组合路由更加灵活,但耦合度比方案1稍高。
内容的提问来源于stack exchange,提问作者synapse
相关产品推荐
相关产品推荐

