使用 Spring 框架的 WebSocketClient 时如何修复 NoClassDefFoundError

How can I fix NoClassDefFoundError when using Spring framework's WebSocketClient

我正在编写桌面 Java 应用程序作为 Web 服务客户端。我想使用 WebSocket 从服务器实现通知 "callback"。

我正在使用 Spring 框架的 WebSocketStompClient。下面的片段显示了我是如何初始化它的:

import org.springframework.web.socket.messaging.WebSocketStompClient;
import org.springframework.web.socket.sockjs.client.SockJsClient;
import org.springframework.web.socket.sockjs.client.Transport;
import org.springframework.web.socket.sockjs.client.WebSocketTransport;
...
List<Transport> transports = new ArrayList<>();
transports.add(new WebSocketTransport(new StandardWebSocketClient()));
stompClient = new WebSocketStompClient(new SockJsClient(transports));
...

如果我在 IntelliJ IDE 中 运行 它工作完美,但是,如果我通过命令行 运行 "java -cp my.jar MyPackage.MyMainClass",它将失败并显示以下消息:

Error: Unable to initialize main class MyMainClass
Caused by: java.lang.NoClassDefFoundError: org/springframework/web/socket/client/WebSocketClient

以上内容由 Java SE 12.0.2 生成。如果我 运行 它使用 Java SE 1.8,错误消息将是:

Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: 
org/springframework/web/socket/client/WebSocketClient
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
    at java.lang.Class.privateGetMethodRecursive(Unknown Source)
    at java.lang.Class.getMethod0(Unknown Source)
    at java.lang.Class.getMethod(Unknown Source)
    at sun.launcher.LauncherHelper.validateMainClass(Unknown Source)
    at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)

java.lang.NoClassDefFoundErrorgetDeclaredMethods0(Native Method) 都表明缺少本机模块(DLL)。

下面是我的 Gradle 脚本:

dependencies {
    implementation project(':logman-common')
    implementation 'org.springframework:spring-web:5.2.2.RELEASE'
    implementation 'org.springframework:spring-websocket:5.2.2.RELEASE'
    implementation 'org.springframework:spring-messaging:5.2.2.RELEASE'
    ... // other unrelated dependencies, such as GUI
}

我不认为这是因为缺少一些 JAR。我试过了:

但错误依旧。

我想我的 OS (Win10) 中缺少一些本地库,但这无法解释为什么我可以 运行 它在 IntelliJ 中...

你能告诉我缺少什么吗?或者我该如何解决这个问题?谢谢!

尝试创建一个包含所有依赖项和 classes 的 fat jar。

build.gradle 脚本更新为如下所示:

apply plugin: 'java'
version = '...'
sourceCompatibility = 1.8
targetCompatibility = 1.8

// to create a fat jar.
jar {
  manifest { 
    attributes "Main-Class": "MyPackage.MyMainClass"
  }  

  from {
    configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
  }
} 

dependencies {
    implementation project(':logman-common')
    implementation 'org.springframework:spring-web:5.2.2.RELEASE'
    implementation 'org.springframework:spring-websocket:5.2.2.RELEASE'
    implementation 'org.springframework:spring-messaging:5.2.2.RELEASE'
    ... // other unrelated dependencies, such as GUI
}

它将在根项目的 build/libs 中生成一个可执行的 fat jar,其中将包含所有项目文件(这包括所有依赖项、资源文件、.class 文件等上)。

注意: 对于旧版本的 Gradle,请使用此 configurations.compile.collect 而不是 configurations.runtimeClasspath.collect

你只需要用这个命令 运行 jar : java -jar <project-version>.jar

这应该可以解决您的问题。

错误消息显示 a JNI error has occurred,因此这确实与本机程序集有关(您可以使用 LLDB 进行调试)。虽然我认为该库可能需要 Java EE 而不会在 Java SE 上 运行;可能与 Tyrus and other JSR 356 implementations. Either switch to another WebSocket implementation, which is known to work with desktop Java SE or write your own; the WebSocket HBYI protocol isn't that difficult; Java SE 11 even has a WebSocket.Builder.

相同