ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • airframe-di: Dependency Injection
    scala/airframe 2022. 11. 19. 22:42

     airframe-di 를 이용한 Dependency Injection

    maven repo: https://mvnrepository.com/artifact/org.wvlet.airframe/airframe

     

    아래정도 기능만 사용하는 것이 좋을 것 같다.

    https://wvlet.org/airframe/docs/airframe-di#child-sessions 등을 사용하면 테스트나 코드 읽기가 힘들어질 것 같다.

     

    Note:

    • +(add) operator 로 design 을 합치거나 override(lazy) 할 수 있다.
    • lazy 하게 적용되기 때문에, 필요한 components 를 나중에 +(add) operator  로 제공되어도 괜찮다.
    • bind[T].toProvider(...) 이것 덕분에 복잡할 수 있는 코드가 많이 간결해 진다.
    import wvlet.airframe._
    
    object ScalaApp {
      type Env = String
    
      case class Config(id: String, ip: String, port: Int)
    
      class App(config: Config, urlMaker: UrlMaker, remoteQuery: RemoteServer) {
        def run(): Unit = {
          println(s"ID: ${config.id}")
          val url  = urlMaker.getURL
          val info = remoteQuery.getInfo(url)
          println(s"INFO: $info")
        }
      }
    
      private class UrlMaker(config: Config) {
        def getURL: String = s"http://${config.ip}:${config.port}/${config.id}"
      }
    
      class RemoteServer(val env: Env, id: String) {
        def getInfo(url: String): String = s"RESPONSE [server=$id]: $url"
      }
    
      def main(args: Array[String]): Unit = {
        val coreDesign: Design = newDesign
          .bind[Config].toInstance(Config("id_123", "127.0.0.1", 8080)) // Lazy
          .bind[UrlMaker].toSingleton
          // Env 가 core Design 에 없더라도 '+' operator 로 나중에 제공되어도 좋다!!
          .bind[RemoteServer]
          .toProvider((config: Config, env: Env) => new RemoteServer(env, config.id))
          .onInit { x: RemoteServer => println(s"Start Remote [${x.env}] Server") }
          .onShutdown { x: RemoteServer => println(s"Stop Remote [${x.env}] Server") }
    
        val devMode: Design = newDesign
          .bind[Env].toInstance("dev")
    
        val prodMode: Design = newDesign
          .bind[Env].toInstance("prod")
    
        //    val design = coreDesign + devMode
        val design = coreDesign + prodMode // 혹은 val design = coreDesign.bind[Env].toInstance("prod")
        design.build[App](app => app.run())
      }
    }

     

    아래처럼 trait 안에서 bind 를 사용해 dependency 를 설정할 수 있다.

    import org.apache.spark.sql.{Dataset, SparkSession}
    import wvlet.airframe.bind
    
    trait RecordWriter[A] {
      val spark: SparkSession = bind[SparkSession]
    
      def write(ds: Dataset[A]): Unit
    }
    
    class ConsoleRecordWriter[A] extends RecordWriter[A] {
      override def write(ds: Dataset[A]): Unit = ds.show()
    }
    
    class HdfsRecordWriter[A](path: String) extends RecordWriter[A] {
      override def write(ds: Dataset[A]): Unit = ds.write.parquet(path)
    }

     

    'scala > airframe' 카테고리의 다른 글

    airframe-control: Retry  (0) 2023.07.06
    airframe-control: Parallel  (0) 2023.07.06

    댓글

Designed by Tistory.