2014-01-30 4 views
6

Ich backe gerade mein erstes Kuchenmuster, also bitte tragen Sie mit mir.Kuchenmuster w/akka: Impliziertes actorSystem mehreren Schichten zur Verfügung stellen

Ich nahm meine monolithische App und ich schnitt sie in funktionelle Schichten. Der Schnitt sieht sauber aus, führt jedoch zu zwei Schichten, die von einem impliziten ActorSystem abhängen.

Ich habe versucht, diese Abhängigkeit so zu lösen:

trait LayerA { 
    this: ActorSystemProvider => 
    private implicit val implicitActorSystem = actorSystem 
    import implicitActorSystem.dispatcher // implicit execution ctx 
    ... 
} 

... und in ähnlicher Weise für LayerX

Meine Montag Klasse wie folgt aussieht:

class Assembly extends LayerA with LayerB with LayerX with ActorSystemProvider 

wo ActorSystemProvider einfach instanziert die Schauspieler System.

Dies funktioniert nicht, da ActorSystem nicht existiert, wenn die Abhängigkeiten aufgelöst und die Werte instanziiert werden, was zu einer NPE führt. Das sieht auch sehr hässlich aus und ich bin mir sicher, dass es einen schöneren und einfacheren Weg geben muss, damit umzugehen.

Wie sollte ich mit geteilten impliziten Abhängigkeiten zwischen den Schichten umgehen, wenn Sie das Kuchenmuster verwenden, wie in diesem Fall ActorSystem?

Dank

Antwort

10

Eigenart keine Voraussetzung ist eine verkrustete Architektur für den Aufbau, eigentlich verwende ich selbst Typen nur in den Fällen, wenn ein Merkmal Bestandteil einer Schicht ist. Wenn ich also implizit in den Anwendungsbereich etwas legen müssen (zum Beispiel ActorRefFactory für Spray-Client) i mischen nur ein Merkmal in:

trait ActorSystemProvider { 
    implicit def actorSystem: ActorSystem 
} 

Und auf der untersten Ebene (so genannte „Ende der Welt“) Ich habe der folgende Code-Struktur:

trait ServiceStack 
    extends SomeModule 
    with SomeModule2 
    with SomeModule3 
    with ActorSystemProvider 

object ServiceLauncher extends App with ServiceStack { 
    val actorSystem = ActorSystem("ServiceName") 
} 

Es ist eine stark vereinfachte Beispiel (wenn Sie ein großartiges Beispiel eines realen Systems bauen auf einem Kuchen-Muster wollen, dann nehmen Sie sollten auf jeden Fall einen Blick auf die Precog System, example wo verschiedene Module/layers verbindet), aber Sie können das ActorSystem bei Bedarf nicht mischen.

+0

@Alexv Ich verstehe nicht, wo Sie 'ActorSystemProvider' verweisen - wie ich dann auf das' actorSystem' von einem internen Merkmal wie 'myInternalCalculator' zugreifen, es wird tief in der Aufrufhierarchie verwendet. – Jas

+0

@Jas Es sieht so aus, als sollte es "mit ActorSystemProvider" anstelle von "ActorRefProvider" sein. Dann können Sie es in etwas ähnlich wie 'ServiceLauncher' initiieren – 4lex1v

5

Wenn Sie die vals als eifrig träge eher instanziieren können, können Sie die implicitActorSystem eine faule val anstelle einer val machen. Es wird also nur ausgeführt, wenn es das erste Mal aufgerufen wird. Ich denke, das sollte das Problem der NPE lösen. (Eine andere wenig bekannte interessante Tatsache, die von @ViktorKlang FYI: Wenn die Initialisierung eines Lazy Val eine Ausnahme auslöst, wird es versuchen, das Val beim nächsten Zugriff neu zu initialisieren.)

Eine andere Möglichkeit wäre, jede Ihrer Methoden zu machen die braucht Ausführungskontext eine implizite ExecutionContext akzeptieren wie:

trait LayerA { 
    def getUser(id: Int)(implicit ec: ExecutionContext) = { 
    ... 
    } 
} 
Verwandte Themen