LoginSignup
1
0

More than 3 years have passed since last update.

[Scala] ActorMaterializerのDIがうまくいかない

Last updated at Posted at 2019-07-25
@singleton
class Hoge @Inject() (implicit system: ActorSystem, materializer: ActorMaterializer) {
  def fuga = Try {
    Http().singleRequest(
      HttpRequest(method = HttpMethods.GET, uri = "https://mikeneko.tk"
    )
  }
}

で実行すると以下のエラー

ProvisionException: Unable to provision, see the following errors:

No implementation for akka.stream.ActorMaterializer was bound.

ActorMaterializer のimplicitがないってエラーになります。
IntelliJでもちゃんとあるって判定はされているのですが・・・

調べてみても同じ記述方法でやってる人はいますね。
* https://blog.colinbreck.com/integrating-akka-streams-and-akka-actors-part-ii/
* https://www.programcreek.com/scala/akka.stream.ActorMaterializer

ハマる(1回目)

色々試してみてわかったのですが、ActorMaterialは () の宣言で挙動が変わってきそうです。
一回外に出して確認してみます。

// これは通る
@singleton
class Hoge @Inject() (implicit system: ActorSystem) {
  implicit val materializer = ActorMaterializer()
  def fuga = Try {
    Http().singleRequest(
      HttpRequest(method = HttpMethods.GET, uri = "https://mikeneko.tk"
    )
  }
}
// これは通らない(ActorMaterializerにかっこがないだけ)
@Singleton
class Hoge @Inject() (implicit system: ActorSystem) {
  implicit val materializer = ActorMaterializer
  def fuga = Try {
    Http().singleRequest(
      HttpRequest(method = HttpMethods.GET, uri = "https://mikeneko.tk"
    )
  }
}

// 結果
could not find implicit value for parameter materializer: 
akka.stream.ActorMaterializer

つまり ActorMaterializer はActorMaterializerとして判断されておらず、 ActorMaterializer() で判断されるようになるみたいです。

理由として、 ActorMaterializer() は applyが呼ばれるのですが、 ActorMaterializer だとただオブジェクトを呼んでいるだけっぽいです。
applyできずに、エラーになっているっぽいですね。ただのオブジェクトをimplicitとして渡されても困るって感じでしょうか。

object ActorMaterializer {

  def apply(materializerSettings: Option[ActorMaterializerSettings] = None, namePrefix: Option[String] = None)(implicit context: ActorRefFactory): ActorMaterializer = {
    val system = actorSystemOf(context)

    val settings = materializerSettings getOrElse ActorMaterializerSettings(system)
    apply(settings, namePrefix.getOrElse("flow"))(context)
  }

  ...
}

ActorSystemがカッコ無しで通るのは、抽象クラスになっていてそもそもの作りが全然違うからでした。

abstract class ActorSystem extends ActorRefFactory {

  ...
}

更にハマる(2回目)

ならカッコ付きで宣言したらOK って思ったのですがここで新たな問題として @Inject() の後ろでimplicitとして定義したいのですがこの中で ActorMaterializer() という記述は使えません。カッコが使えないのです。(何故?)

ActorSystemはかっこなしとありで挙動が変わらなかったのでここに書いていますが、ActorMaterializerに関しては変わるので外に出すことにしました。やってることは同じなはず・・・

@singleton
class Hoge @Inject() (implicit system: ActorSystem) {
  implicit val materializer = ActorMaterializer()
  def fuga = Try {
    Http().singleRequest(
      HttpRequest(method = HttpMethods.GET, uri = "https://mikeneko.tk"
    )
  }
}

一旦これで。
毎回 ActorMaterializerを生成するのを防ぎたいという目標自体はクリアでき他のでこれでOKとします。

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0