为什么 OSGI 与 ActorSystemActivator 的捆绑在启动时因 Logger 超时而失败?

Why does OSGI bundle with ActorSystemActivator fail with Logger timeout upon start?

我使用 akka-osgi_2.10-2.3.4 库和所有需要的依赖项在 Scala 中编写了一个 OSGI "Hello World" 应用程序。实际上这里是所有依赖项 maven 报告:

+- com.typesafe.akka:akka-actor_2.10:jar:2.3.4:compile
|  \- com.typesafe:config:jar:1.2.1:compile
+- com.typesafe.akka:akka-slf4j_2.10:jar:2.3.4:compile
|  \- org.slf4j:slf4j-api:jar:1.7.5:compile
+- org.apache.felix:org.osgi.core:jar:1.4.0:compile
+- com.typesafe.akka:akka-osgi_2.10:jar:2.3.4:compile
|  +- org.osgi:org.osgi.core:jar:4.3.1:compile
|  \- org.osgi:org.osgi.compendium:jar:4.3.1:compile
+- org.scala-lang:scala-library:jar:2.10.4:compile

该应用程序使用最简单的 Activator class,利用 ActorSystemActivator 提供的默认 startstop 方法。 Activator class 代码如下所示:

import akka.actor.ActorSystem
import org.osgi.framework.BundleContext
import akka.osgi.ActorSystemActivator

class Activator extends ActorSystemActivator {

  def configure(bundleContext: BundleContext, system: ActorSystem): Unit = {
  }
}

我使用 IBM JDK 1.7,在 eclipse juno-64(在 ubuntu 12.04)环境中,我在 config.ini 中设置了 bootdelegation,如官方 documentation:

org.osgi.framework.bootdelegation=sun.misc

我使用 -console 参数启动了 Eclipse,并在 OSGi 框架中部署了捆绑的应用程序。这是我在 OSGi 控制台中运行 ss 时得到的结果:

426     <<LAZY>>    test-osgi_0.0.1.SNAPSHOT

我遇到的问题是启动捆绑包。当我尝试启动它时:

osgi> start 426

我收到 Akka 超时异常:

[WARN] [01/06/2015 15:04:02.530] [Gogo shell] [EventStream(akka://bundle-426-ActorSystem)] Logger log1-Logging$DefaultLogger did not respond within Timeout(25000 milliseconds) to InitializeLogger(bus)
error while starting up loggers
akka.ConfigurationException: Logger specified in config can't be loaded [akka.event.Logging$DefaultLogger] due to [akka.event.Logging$LoggerInitializationException: Logger log1-Logging$DefaultLogger did not respond with LoggerInitialized, sent instead [TIMEOUT]]
    at akka.event.LoggingBus$$anonfun$$anonfun$apply.applyOrElse(Logging.scala:114)
    at akka.event.LoggingBus$$anonfun$$anonfun$apply.applyOrElse(Logging.scala:113)
    at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:33)
...

我上网查了一下,发现了与我类似的问题,但建议的解决方案都不适合我。我尝试将默认记录器响应超时修改为不同的值,我将 DefaultLogger 更改为其他版本 (DefaultOSGiLogger),我添加了 org.osgi.framework.system.packages.extra=sun.misc 配置,但是没有任何帮助。 我也尝试了 akka-sample-osgi-dining-hakkers 示例,但我遇到了 OSGi 噩梦...... 我错过了什么?

sschaef(谢谢)所附link中的信息帮助解决了这个问题。这是一种解决方法,可以在不破解依赖库的情况下启动 Akka 系统。如该线程中所述,显然是 class 加载程序问题,解决方案(我遵循的)使用侦听器来激活系统。

我仍然扩展了 ActorSystemActivator(虽然这可以避免,正如 sschaef 所指出的那样)并且我在重写的启动和停止方法中重用了扩展 class 中的代码。这是对我有用的代码:

class Activator extends ActorSystemActivator {

  private var system: Option[ActorSystem] = None
  @volatile var bundleListener: org.osgi.framework.BundleListener = null

  def configure(bundleContext: BundleContext, system: ActorSystem): Unit = {}
  override def getActorSystemName(context: BundleContext): String = "my-actor-system"

  override def start(context: BundleContext) = {
    bundleListener = new org.osgi.framework.BundleListener() {
      override def bundleChanged(event: org.osgi.framework.BundleEvent) {
        if (event.getBundle == context.getBundle) {
          if (event.getType == org.osgi.framework.BundleEvent.STARTED) {
            system = Some(OsgiActorSystemFactory(context, getActorSystemConfiguration(context)).createActorSystem(Option(getActorSystemName(context))))
            system foreach (addLogServiceListener(context, _))
            system foreach (configure(context, _))
          }
        }
      }
    }
    context.addBundleListener(bundleListener)
  }

  override def stop(context: BundleContext) = {
    if (bundleListener != null)
      context.removeBundleListener(bundleListener)
    system foreach (_.shutdown())
  }
}