我正在烘焙我的第一个蛋糕图案,所以请耐心等待。
我使用了我的单片应用程序,并将其剪切为功能层。剪切看起来很干净但导致两个依赖于隐式ActorSystem的层。
我试图像这样解决这种依赖:
trait LayerA {
this: ActorSystemProvider =>
private implicit val implicitActorSystem = actorSystem
import implicitActorSystem.dispatcher // implicit execution ctx
...
}
......和LayerX
类似我的汇编类看起来像:
class Assembly extends LayerA with LayerB with LayerX with ActorSystemProvider
其中ActorSystemProvider只是实例化actor系统。
这不起作用,因为当解析依赖关系并且实例化val时,ActorSystem
不存在,从而导致NPE。这看起来也很丑陋,我确信必须有一个更好/更简单的方法来处理它。
在使用蛋糕模式时,如何处理图层之间的共享隐式依赖关系,例如ActorSystem
?
由于
答案 0 :(得分:10)
自我类型不是构建结构化体系结构的必要条件,实际上我只在特征是图层组件的情况下使用自我类型。所以当我需要将一些隐含的东西放入范围时(例如Spray Client的ActorRefFactory)我只是混合了一个特征:
trait ActorSystemProvider {
implicit def actorSystem: ActorSystem
}
在最低层(所谓的“世界末日”)上,我有以下代码结构:
trait ServiceStack
extends SomeModule
with SomeModule2
with SomeModule3
with ActorSystemProvider
object ServiceLauncher extends App with ServiceStack {
val actorSystem = ActorSystem("ServiceName")
}
这是一个过于简单的例子(如果你想要一个基于蛋糕模式的真实系统构建的一个很好的例子,那么你一定要看看Precog系统,example其中不同的模块/图层连接),但不是你可以在需要时混合使用隐式ActorSystem。
答案 1 :(得分:5)
如果你可以懒得而不是急切地实例化val,你可以使implicitActorSystem成为一个懒惰的val而不是val。所以它只在第一次访问时执行。我认为这应该解决NPE的问题。 (@ViktorKlang FYI发布的另一个鲜为人知的有趣事实:如果lazy val的初始化抛出异常,它将尝试在下次访问时重新初始化val。)
另一种方法是使每个需要执行上下文的方法接受隐式的executionContext,如:
trait LayerA {
def getUser(id: Int)(implicit ec: ExecutionContext) = {
...
}
}