【问题标题】:Scala-cat's IOApp in an OSGi contextOSGi 上下文中的 Scala-cat 的 IOApp
【发布时间】:2019-07-23 15:41:30
【问题描述】:

我目前正在开发的一个应用程序是使用scala-cats'IOApp 以函数式编程风格编写的。

现在的问题是我需要将这个应用程序部署在一个似乎并不真正适合我的功能方法的 OSGi 上下文中。

我的主要方法是这样的:

object Main extends IOApp {
  override def run(args: List[String]): IO[ExitCode] = for {
    _ <- IO(println("Starting with args: " + args.mkString(",")))
    myProgram = new MyProgram(/*...*/)
    _ <- myProgram.run() // def run(): IO[RunResult]
    // ...
    _ <- myProgram.exit() // def exit(): IO[Unit]
    } yield ExitCode.Success
}

现在要将它部署到 OSGi,我必须写一个 BundleActivator

import org.osgi.framework.{BundleActivator, BundleContext}

class Activator extends BundleActivator {

  private var myProgram: Option[myProgram] = None

  override def start(context: BundleContext): Unit = {
    myProgram = Some(new MyProgram(/*...*/))
    myProgram.foreach{ _.run().unsafeRunSync() }
  }

  override def stop(context: BundleContext): Unit = {
    myProgram.foreach{ _.exit().unsafeRunSync() }
  }
}

如您所见,我想出的Activator 远非以功能性方式编写。有什么办法至少可以摆脱var myProgram(具体来说是可变的var)?我似乎无法弄清楚这怎么可能。

编辑: 激活器需要在manifest中定义,所以这是我build.sbt的一部分:

packageOptions := Seq(ManifestAttributes(
  ("Bundle-Activator", "my.package.Activator"),
  ...)) 

【问题讨论】:

  • 考虑定制一个cats.effect.Resource 来代表BundleActivator`
  • 另外,我仍然明白为什么您使用varOptionIO 很懒。
  • @V-Lamp 你说的没有道理。您将不得不指向清单中的激活器,那么Resource 是从哪里来的? IO的懒惰与这里使用varOption有什么关系?
  • 我的 cmets 在显示 packageOptions 的编辑之前,我现在看到它没有意义 :)
  • 澄清一下:上面的代码运行良好!在我看来,这还不够“纯”/FP。

标签: scala functional-programming osgi scala-cats io-monad


【解决方案1】:

这里没有办法避免一些讨厌的 Java 式代码,这就是 OSGi 的工作原理。但是你能做的就是把讨厌的东西隐藏在一个可重用的类中,所以你只需要把它弄好一次就不会再看它了。我的建议是一个通用的 Activator,它会在启动时获取一只猫 Resource,并在你关闭它时将其丢弃。

class ResourceActivator(resource: BundleContext => Resource[IO, Unit])
  extends BundleActivator {

  private var cleanup: IO[Unit] = null

  override def start(context: BundleContext): Unit =
    cleanup = resource(context).allocate.unsafeRunSync()._2

  override def stop(context: BundleContext): Unit =
    cleanup.unsafeRunSync()
}

有效的 OSGi 实现永远不会在不先调用start 的情况下调用stop,因此可以将cleanup 初始化为null

请注意,上面的类很容易让你 e. G。在start 方法中启动一些异步计算并在stop 方法中关闭它:

class MyActivator extends ResourceActivator(ctx =>
  for {
    res1 <- someResource
    res2 <- anotherResource
    _ <- Resource.make(doSomeStuff.start)(_.cancel)
  } yield ()
)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-30
    • 2021-09-19
    • 1970-01-01
    • 2011-04-16
    • 2013-11-14
    • 2018-07-11
    • 2011-09-25
    • 2011-02-28
    相关资源
    最近更新 更多