无法使用激活器加载本机库(Play Framework)
fail to load a native library using activator (Play Framework)
我正在尝试在我的 Play 2.4.x 应用程序中加载本机库。我写了一个简单的测试,在 IDE (IntelliJ) 和 SBT 中都运行良好。在这两种情况下,我都将 java.library.path
设置为 运行.
在IDE中,我在测试运行配置中设置了-Djava.library.path=$USER_HOME$/dev/lindoapi/bin/linux64
。
根据 sbt 文档,我的 build.sbt
正在分叉 JVM 并设置 java.library.path
。
javaOptions += "-Djava.library.path=/home/aczerwon/dev/lindoapi/bin/linux64"
fork := true
以下测试在 IDE 和 activator test
中都顺利通过。
class LindoApiSpec extends Specification {
System.loadLibrary("lindojni")
"The Lindo API" should {
"have a valid license" in {
val lindo = new LindoEnvironment()
lindo.apiVerion() must beSuccessfulTry.withValue("LINDO API Version 9.0.2120.225")
}
}
在测试上下文之外时,我在 Play 的启动生命周期中加载本机库。
object Global extends GlobalSettings {
override def beforeStart(app: Application) = {
System.loadLibrary("lindojni")
}
}
当我从网络调用相同的方法时api (activator ~run
),我收到了 UnsatisfiedLinkError
错误。
1) Error injecting constructor, java.lang.UnsatisfiedLinkError: no lindojni in java.library.path
at play.api.GlobalPlugin.<init>(GlobalSettings.scala:262)
at play.api.GlobalPlugin.class(GlobalSettings.scala:262)
while locating play.api.GlobalPlugin
网络 api 看起来像这样:
class OptimizationApi extends Controller {
def version() = Action {
val lindo = new LindoEnvironment()
lindo.apiVerion() match {
case Success(version) => Ok(version)
case Failure(e) => BadRequest(e.getMessage)
}
}
}
我假设我的 build.sbt 会分叉 JVM 并为 both test
and[ 设置 java.library.path
=51=] run
上下文。关于我做错了什么的任何线索?
新信息
当我启动 activator -Djava.library.path=$USER_HOME$/dev/lindoapi/bin/linux64
或设置 JAVA_OPTS 时,启动生命周期中对 System.loadLibrary(...)
的调用通过。我仍然得到 UnsatisfiedLinkError
,但稍后当我通过 JNI 调用本机库时会发生这种情况。很奇怪。
我找到了问题的解决方案 here。
本机库及其 java 副本必须在同一个 class 加载器中。
创建一个 class 类似于:
public final class PlayNativeLibraryLoader {
public static void load(String libraryPath) {
System.load(libraryPath);
}
}
现在您可以在 Play 启动生命周期中使用它了。
object Global extends GlobalSettings {
override def beforeStart(app: Application) = {
PlayNativeLibraryLoader.load(app.getFile("./lib/lindoapi/linux64/liblindojni.so").getPath)
Logger.info("Lindo native library loaded")
}
}
我正在尝试在我的 Play 2.4.x 应用程序中加载本机库。我写了一个简单的测试,在 IDE (IntelliJ) 和 SBT 中都运行良好。在这两种情况下,我都将 java.library.path
设置为 运行.
在IDE中,我在测试运行配置中设置了-Djava.library.path=$USER_HOME$/dev/lindoapi/bin/linux64
。
根据 sbt 文档,我的 build.sbt
正在分叉 JVM 并设置 java.library.path
。
javaOptions += "-Djava.library.path=/home/aczerwon/dev/lindoapi/bin/linux64"
fork := true
以下测试在 IDE 和 activator test
中都顺利通过。
class LindoApiSpec extends Specification {
System.loadLibrary("lindojni")
"The Lindo API" should {
"have a valid license" in {
val lindo = new LindoEnvironment()
lindo.apiVerion() must beSuccessfulTry.withValue("LINDO API Version 9.0.2120.225")
}
}
在测试上下文之外时,我在 Play 的启动生命周期中加载本机库。
object Global extends GlobalSettings {
override def beforeStart(app: Application) = {
System.loadLibrary("lindojni")
}
}
当我从网络调用相同的方法时api (activator ~run
),我收到了 UnsatisfiedLinkError
错误。
1) Error injecting constructor, java.lang.UnsatisfiedLinkError: no lindojni in java.library.path
at play.api.GlobalPlugin.<init>(GlobalSettings.scala:262)
at play.api.GlobalPlugin.class(GlobalSettings.scala:262)
while locating play.api.GlobalPlugin
网络 api 看起来像这样:
class OptimizationApi extends Controller {
def version() = Action {
val lindo = new LindoEnvironment()
lindo.apiVerion() match {
case Success(version) => Ok(version)
case Failure(e) => BadRequest(e.getMessage)
}
}
}
我假设我的 build.sbt 会分叉 JVM 并为 both test
and[ 设置 java.library.path
=51=] run
上下文。关于我做错了什么的任何线索?
新信息
当我启动 activator -Djava.library.path=$USER_HOME$/dev/lindoapi/bin/linux64
或设置 JAVA_OPTS 时,启动生命周期中对 System.loadLibrary(...)
的调用通过。我仍然得到 UnsatisfiedLinkError
,但稍后当我通过 JNI 调用本机库时会发生这种情况。很奇怪。
我找到了问题的解决方案 here。
本机库及其 java 副本必须在同一个 class 加载器中。
创建一个 class 类似于:
public final class PlayNativeLibraryLoader {
public static void load(String libraryPath) {
System.load(libraryPath);
}
}
现在您可以在 Play 启动生命周期中使用它了。
object Global extends GlobalSettings {
override def beforeStart(app: Application) = {
PlayNativeLibraryLoader.load(app.getFile("./lib/lindoapi/linux64/liblindojni.so").getPath)
Logger.info("Lindo native library loaded")
}
}