Spring Netbeans 运行 上的应用程序 java.lang.UnsatisfiedLinkError
Spring application java.lang.UnsatisfiedLinkError on Netbeans run
我们有一个使用 OR-Tools 的应用程序,它由几个模块组成(maven,所有这些都是 Spring 引导模块),特别是:
- 优化器模块,通过以下代码加载or-tools DLL:
public class Optimizer {
static {
try {
// extracts .dll from or-tools-windows jar and copies it into C:\users\my-user\AppData\Local\Temp\temp_ortools
// calls System.load("C:\users\my-user\AppData\Local\Temp\temp_ortools\jniortools.dll")
carregaBibliotecasORTools();
} catch (Exception e) {
log.info(e.getMessage());
} catch (Error e) {
log.info(e.getMessage());
}
}
public static OptimizerData getOptimizerData() {
OptimizerData optimizerData = new OptimizerData();
System.out.println("Instantiating Solver");
optimizerData.solver = MPSolver.createSolver("SCIP");
System.out.println("Solver Instantiated");
return optimizerData;
}
}
- 服务模块,使用:
@Service
public class PlanningService{
public void executePlan() {
OptimizerData optimizerData = Optimizer.getOptimizerData();
...
}
}
- web 模块(spring-boot-starter-web 依赖项),使服务可通过控制器使用
我们已成功运行以下情况的代码:
- 运行 优化器模块上的测试方法(在 netbeans 上),它调用
getOptimizerData
方法
- 使用 3 个模块(通过在 netbeans 上构建 web 模块)生成一个 fat jar 并 运行ning 这个 fat jar。端点调用工作正常
但是,当我们 运行 Netbeans 上的 Web 模块时,调用端点时会显示以下错误消息:
2021-05-09 22:59:38.587 ERROR 19300 --- [nio-8020-exec-8] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.UnsatisfiedLinkError: com.google.ortools.linearsolver.main_research_linear_solverJNI.MPSolver_createSolver(Ljava/lang/String;)J] with root cause
一些重要的观察结果:
- 考虑到 fat jar 工作正常,这似乎是 netbeans 特有的问题
- 我们执行了以下方法 (System.load) 以验证库是否确实已加载:
public static void listAllLoadedNativeLibrariesFromJVM() {
ClassLoader appLoader = ClassLoader.getSystemClassLoader();
ClassLoader currentLoader = LibraryLoader.class.getClassLoader();
ClassLoader[] loaders = new ClassLoader[] { appLoader, currentLoader };
for (int i=0; i<loaders.length; i++) {
final String[] libraries = ClassScope.getLoadedLibraries(loaders[i]);
for (String library : libraries) {
System.out.println("Loader " + loaders[i].getClass().getName() + " : " + library);
}
}
}
此方法的结果是:
- 优化器模块中的测试文件(运行良好):
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\zip.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Users\my-user\AppData\Local\Temp\temp_ortools\jniortools.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\zip.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Users\my-user\AppData\Local\Temp\temp_ortools\jniortools.dll
- 通过编译 web 模块生成的 Fat .jar(运行良好):
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jre1.8.0_281\bin\zip.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jre1.8.0_281\bin\management.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jre1.8.0_281\bin\net.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jre1.8.0_281\bin\nio.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Users\my-user\AppData\Local\Temp\temp_ortools\jniortools.dll
Loader org.springframework.boot.loader.LaunchedURLClassLoader : C:\Program Files\Java\jre1.8.0_281\bin\zip.dll
Loader org.springframework.boot.loader.LaunchedURLClassLoader : C:\Program Files\Java\jre1.8.0_281\bin\management.dll
Loader org.springframework.boot.loader.LaunchedURLClassLoader : C:\Program Files\Java\jre1.8.0_281\bin\net.dll
Loader org.springframework.boot.loader.LaunchedURLClassLoader : C:\Program Files\Java\jre1.8.0_281\bin\nio.dll
Loader org.springframework.boot.loader.LaunchedURLClassLoader : C:\Users\my-user\AppData\Local\Temp\temp_ortools\jniortools.dll
- Netbeans 'run' Web 模块上的命令
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\zip.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\management.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\net.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\nio.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Users\my-user\AppData\Local\Temp\temp_ortools\jniortools.dll
Loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\zip.dll
Loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\management.dll
Loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\net.dll
Loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\nio.dll
Loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader : C:\Users\my-user\AppData\Local\Temp\temp_ortools\jniortools.dll
通过比较 listAllLoadedNativeLibrariesFromJVM 调用的最后 2 个输出,加载的 fat jar 和 netbeans 之间存在细微差别 类,具体而言:
- Netbeans 运行 :
Loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader : C:\Users\my-user\AppData\Local\Temp\temp_ortools\jniortools.dll
- 胖罐子运行 :
Loader org.springframework.boot.loader.LaunchedURLClassLoader : C:\Users\my-user\AppData\Local\Temp\temp_ortools\jniortools.dll
根据这些日志,我们确定以下依赖项是导致问题的原因:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
此依赖项允许 Spring 应用程序在代码更改的情况下更快地重新启动。通过删除此依赖项,应用程序 运行s 在 Netbeans 上没有任何问题。
欢迎任何关于如何使 Spring Boot Devtools 使用静态加载的 .dll 库的见解。
我们有一个使用 OR-Tools 的应用程序,它由几个模块组成(maven,所有这些都是 Spring 引导模块),特别是:
- 优化器模块,通过以下代码加载or-tools DLL:
public class Optimizer {
static {
try {
// extracts .dll from or-tools-windows jar and copies it into C:\users\my-user\AppData\Local\Temp\temp_ortools
// calls System.load("C:\users\my-user\AppData\Local\Temp\temp_ortools\jniortools.dll")
carregaBibliotecasORTools();
} catch (Exception e) {
log.info(e.getMessage());
} catch (Error e) {
log.info(e.getMessage());
}
}
public static OptimizerData getOptimizerData() {
OptimizerData optimizerData = new OptimizerData();
System.out.println("Instantiating Solver");
optimizerData.solver = MPSolver.createSolver("SCIP");
System.out.println("Solver Instantiated");
return optimizerData;
}
}
- 服务模块,使用:
@Service
public class PlanningService{
public void executePlan() {
OptimizerData optimizerData = Optimizer.getOptimizerData();
...
}
}
- web 模块(spring-boot-starter-web 依赖项),使服务可通过控制器使用
我们已成功运行以下情况的代码:
- 运行 优化器模块上的测试方法(在 netbeans 上),它调用
getOptimizerData
方法 - 使用 3 个模块(通过在 netbeans 上构建 web 模块)生成一个 fat jar 并 运行ning 这个 fat jar。端点调用工作正常
但是,当我们 运行 Netbeans 上的 Web 模块时,调用端点时会显示以下错误消息:
2021-05-09 22:59:38.587 ERROR 19300 --- [nio-8020-exec-8] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.UnsatisfiedLinkError: com.google.ortools.linearsolver.main_research_linear_solverJNI.MPSolver_createSolver(Ljava/lang/String;)J] with root cause
一些重要的观察结果:
- 考虑到 fat jar 工作正常,这似乎是 netbeans 特有的问题
- 我们执行了以下方法 (System.load) 以验证库是否确实已加载:
public static void listAllLoadedNativeLibrariesFromJVM() {
ClassLoader appLoader = ClassLoader.getSystemClassLoader();
ClassLoader currentLoader = LibraryLoader.class.getClassLoader();
ClassLoader[] loaders = new ClassLoader[] { appLoader, currentLoader };
for (int i=0; i<loaders.length; i++) {
final String[] libraries = ClassScope.getLoadedLibraries(loaders[i]);
for (String library : libraries) {
System.out.println("Loader " + loaders[i].getClass().getName() + " : " + library);
}
}
}
此方法的结果是:
- 优化器模块中的测试文件(运行良好):
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\zip.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Users\my-user\AppData\Local\Temp\temp_ortools\jniortools.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\zip.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Users\my-user\AppData\Local\Temp\temp_ortools\jniortools.dll
- 通过编译 web 模块生成的 Fat .jar(运行良好):
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jre1.8.0_281\bin\zip.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jre1.8.0_281\bin\management.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jre1.8.0_281\bin\net.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jre1.8.0_281\bin\nio.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Users\my-user\AppData\Local\Temp\temp_ortools\jniortools.dll
Loader org.springframework.boot.loader.LaunchedURLClassLoader : C:\Program Files\Java\jre1.8.0_281\bin\zip.dll
Loader org.springframework.boot.loader.LaunchedURLClassLoader : C:\Program Files\Java\jre1.8.0_281\bin\management.dll
Loader org.springframework.boot.loader.LaunchedURLClassLoader : C:\Program Files\Java\jre1.8.0_281\bin\net.dll
Loader org.springframework.boot.loader.LaunchedURLClassLoader : C:\Program Files\Java\jre1.8.0_281\bin\nio.dll
Loader org.springframework.boot.loader.LaunchedURLClassLoader : C:\Users\my-user\AppData\Local\Temp\temp_ortools\jniortools.dll
- Netbeans 'run' Web 模块上的命令
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\zip.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\management.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\net.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\nio.dll
Loader sun.misc.Launcher$AppClassLoader : C:\Users\my-user\AppData\Local\Temp\temp_ortools\jniortools.dll
Loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\zip.dll
Loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\management.dll
Loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\net.dll
Loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader : C:\Program Files\Java\jdk1.8.0_281\jre\bin\nio.dll
Loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader : C:\Users\my-user\AppData\Local\Temp\temp_ortools\jniortools.dll
通过比较 listAllLoadedNativeLibrariesFromJVM 调用的最后 2 个输出,加载的 fat jar 和 netbeans 之间存在细微差别 类,具体而言:
- Netbeans 运行 :
Loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader : C:\Users\my-user\AppData\Local\Temp\temp_ortools\jniortools.dll
- 胖罐子运行 :
Loader org.springframework.boot.loader.LaunchedURLClassLoader : C:\Users\my-user\AppData\Local\Temp\temp_ortools\jniortools.dll
根据这些日志,我们确定以下依赖项是导致问题的原因:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
此依赖项允许 Spring 应用程序在代码更改的情况下更快地重新启动。通过删除此依赖项,应用程序 运行s 在 Netbeans 上没有任何问题。
欢迎任何关于如何使 Spring Boot Devtools 使用静态加载的 .dll 库的见解。