首页 > 解决方案 > 使用 Spring 框架的 WebSocketClient 时如何修复 NoClassDefFoundError

问题描述

我正在编写一个桌面 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.NoClassDefFoundError建议getDeclaredMethods0(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。我试过:

但错误仍然存​​在。

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

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

标签: javaspringgradlebuild.gradlespring-websocket

解决方案


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

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


推荐阅读