ZLayer[A, E, B]
描述应用程序的一层:应用程序中的每个层都需要一些服务(作为输入)并产生出一些服务(作为输出)。Layers 可以被视基于给定他们的依赖关系(其他服务)而产生这些服务绑定所需要的清单。
层的构造可以使资源的使用效果化,并且使资源被安全地获取,使用完后安全地释放。
默认情况下,层(Layer)是共享的,这意味着如果同一图层使用两次,则该图层将仅分配一次。由于层具有出色的可组合性,因此它们是 ZIO 中创建依赖于其他服务的服务的惯用方式。
最简单的 ZLayer 应用
import zio._
object Example extends zio.App {
def run(args: List[String]): URIO[ZEnv, ExitCode] =
zio.provideLayer(nameLayer).as(ExitCode.success)
val zio = for {
name <- ZIO.access[Has[String]](_.get)
_ <- UIO(println(s"Hello, $name!"))
} yield ()
val nameLayer = ZLayer.succeed("Adam")}
具有依赖项的 ZLayer 应用
import zio._
import zio.console._
import zio.clock._
import java.io.IOException
import zio.duration.Duration._
object moduleA {
type ModuleA = Has[ModuleA.Service]
object ModuleA {
trait Service {
def letsGoA(v: Int): UIO[String]
}
val any: ZLayer[ModuleA, Nothing, ModuleA] =
ZLayer.requires[ModuleA]
val live: Layer[Nothing, Has[Service]] = ZLayer.succeed {
new Service {
def letsGoA(v: Int): UIO[String] = UIO(s"done: v = $v ")
}
}
}
def letsGoA(v: Int): URIO[ModuleA, String] =
ZIO.accessM(_.get.letsGoA(v))
}
import moduleA._
object moduleB {
type ModuleB = Has[ModuleB.Service]
object ModuleB {
trait Service {
def letsGoB(v: Int): UIO[String]
}
val any: ZLayer[ModuleB, Nothing, ModuleB] =
ZLayer.requires[ModuleB]
val live: ZLayer[ModuleA, Nothing, ModuleB] = ZLayer.fromService { (moduleA: ModuleA.Service) =>
new Service {
def letsGoB(v: Int): UIO[String] =
moduleA.letsGoA(v)
}
}
}
def letsGoB(v: Int): URIO[ModuleB, String] =
ZIO.accessM(_.get.letsGoB(v))
}
object ZLayerApp0 extends zio.App {
import moduleB._
val env = Console.live ++ Clock.live ++ (ModuleA.live >>> ModuleB.live)
val program: ZIO[Console with Clock with moduleB.ModuleB, IOException, Unit] =
for {
_ <- putStrLn(s"Welcome to ZIO!")
_ <- sleep(Finite(1000))
r <- letsGoB(10)
_ <- putStrLn(r)
} yield ()
def run(args: List[String]) =
program.provideLayer(env).exitCode
}
// output:
// [info] running ZLayersApp
// Welcome to ZIO!
// done: v = 10
复杂的 ZLayer 依赖案例
import zio._
import zio.clock._
object ZLayerApp1 extends scala.App {
val rt = Runtime.default
type ModuleA = Has[ModuleA.Service]
object ModuleA {
trait Service {}
val any: ZLayer[ModuleA, Nothing, ModuleA] =
ZLayer.requires[ModuleA]
val live: ZLayer[Any, Nothing, ModuleA] =
ZLayer.succeed(new Service {})
}
type ModuleB = Has[ModuleB.Service]
object ModuleB {
trait Service {}
val any: ZLayer[ModuleB, Nothing, ModuleB] =
ZLayer.requires[ModuleB]
val live: ZLayer[Any, Nothing, ModuleB] =
ZLayer.succeed(new Service {})
}
type ModuleC = Has[ModuleC.Service]
object ModuleC {
trait Service {
def foo: UIO[Int]
}
val any: ZLayer[ModuleC, Nothing, ModuleC] =
ZLayer.requires[ModuleC]
val live: ZLayer[ModuleA with ModuleB with Clock, Nothing, ModuleC] =
ZLayer.succeed {
new Service {
val foo: UIO[Int] = UIO.succeed(42)
}
}
val foo: URIO[ModuleC, Int] =
ZIO.accessM(_.get.foo)
}
val env = (ModuleA.live ++ ModuleB.live ++ ZLayer.identity[Clock]) >>> ModuleC.live
val res = ModuleC.foo.provideCustomLayer(env)
val out = rt.unsafeRun(res)
println(out)
// 42
}