I started to use Play 2.5 recently, and I was wondering what the purpose of doing the following was:
@Inject() (implicit val mat: Materializer)
I had several pieces of code not working and solved that issue thanks to this, but I still don't see what the materializer is doing.
Thanks
A materializer makes actors execute a graph to produce those results.
A graph, in its simplest form, consists of a source that provides elements, and a sink that consumes elements.
Here's a source that provides a range of integers (in this example, integers are our elements):
val source = Source(1 to 10)
And here's a sink that sums all the integers it gets from a source:
val sink = Sink.fold[Int, Int](0)(_ + _)
We connect source and sink to get a graph:
val graph = source.toMat(sink)(Keep.right)
Mind that no computation, addition in our case, is performed when creating a graph. The code is declarative, the graphs describe how we want to transform our data but it is someone else's job to actually perform the computation: Graphs are blueprints.
Now, what about the materializer? The materializer takes action when we run the graph:
implicit val materializer = ActorMaterializer() val futureResult = graph.run()
When we run()
the graph, the materializer takes the graph and makes actors execute the data transformations specified in the graph; in this example, that's adding integers.
It might be helpful to imagine the graph as a blueprint to build a house, the materializer as the foreman looking at the blueprint, telling the builders how to actually build the house according to the blueprint. The builders in this analogy correspond to actors in Akka.
The reason why several pieces of your code now work, is that with the materializer you provide a way to execute graphs. Graphs are heavily used in Akka HTTP which Play uses for HTTP requests and responses.
The WSClient you mentioned in your comment uses graphs to perform its requests and thus needs a materializer.
Here's a full example of creating and running a graph:
import akka.actor.ActorSystem import akka.stream.ActorMaterializer import akka.stream.scaladsl.{Keep, Sink, Source} object Graphs extends App { // The start of our simple graph. It provides elements, integers in our case val source = Source(1 to 10) // The end of our graph. It processes the source's elements val sink = Sink.fold[Int, Int](0)(_ + _) /* * Connect source and sink. * Keep only the output values (i.e., the graph's right side). * Note that this is declarative: no result is computed until we run the graph. */ val graph = source.toMat(sink)(Keep.right) // The system coordinates actors and provides threads for them implicit val actorSystem = ActorSystem() // The materializer makes actors execute graphs implicit val materializer = ActorMaterializer() // Running the graph means that the materializer assigns actors to execute // the graph from start (source) to end (sink) val futureResult = graph.run() // Use the actor system's execution context, which provides threads, // to print the result of running the graph implicit val executionContext = actorSystem.dispatcher futureResult.foreach(res => println(s"Result of running the graph: $res")) actorSystem.terminate().foreach(_ => println("System is shut down")) }
Put this in your build.sbt
to make Akka's stream library available in your code:
libraryDependencies += "com.typesafe.akka" %% "akka-stream" % "2.5.19"
Here's more on sources and sinks.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With