9阅网

您现在的位置是:首页 > 知识 > 正文

知识

java - 使用Spring框架的WebSocketClient时,如何修复NoClassDefFoundError?

admin2022-11-07知识16

我正在编写一个桌面Java应用程序作为Web服务客户端。我想使用WebSocket来实现来自服务器的通知 "回调"。

我正在使用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
}

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

  • 添加... tyrus-standalone-client 到依赖关系列表中,或者
  • 使用 StandardWebSocketClient 而不是 SockJsClient,

但错误依然存在。

我猜我的操作系统(Win10)中缺少一些本地库,但这不能解释为什么我可以在IntelliJ中运行它......

你能告诉我缺少了什么吗? 或者我如何解决这个问题?谢谢!我正在编写一个桌面Java应用程序,作为我的操作系统(Win10),但无法解释为什么我可以在IntelliJ中运行它。



【回答】:

试着创建一个包含所有依赖项和类的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
}

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

注意:对于Gradle的旧版本,使用这个文件。 对于旧版本的Gradle,使用这个 configurations.compile.collect 而不是 configurations.runtimeClasspath.collect.

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

这应该解决你的问题。

【回答】:

错误信息如下,即 a JNI error has occurred所以这确实与本地汇编有关(你可以用LLDB调试)。虽然我认为那个库可能需要Java EE,而且不能在Java SE上运行;但很有可能它与 泰鲁斯 及其他 JSR 356 实现。要么切换到另一个 WebSocket 实现(已知可与桌面 Java SE 配合使用),要么编写自己的 WebSocket HBYI 协议并不难;Java SE 11甚至有一个叫做 WebSocket.Builder.