ContainerProvider 的独立 Java Websocket 客户端 NoClassDefFoundError

Posted

技术标签:

【中文标题】ContainerProvider 的独立 Java Websocket 客户端 NoClassDefFoundError【英文标题】:Standalone Java Websocket client NoClassDefFoundError by ContainerProvider 【发布时间】:2015-12-05 17:26:29 【问题描述】:

我是Java新手,但我必须用它来做一个与WebSocket相关的小项目。

所以,我在 VirtualBox 中的 CentOS 7 上安装了 JDK 1.8.0 和 NetBeans 8.1。

我在 pom.xml 中添加了 tyrus-standalone-client-jdk 1.12 插件来制作独立的 Websocket 客户端,并且构建良好。但是,我遇到了以下错误:

[root@cet7 ~]# java -jar "/root/NetBeansProjects/Switchclient/target/Switchclient-1.0-SNAPSHOT.jar"

Exception in thread "main" java.lang.NoClassDefFoundError: javax/websocket/ContainerProvider
    at org.sample.switchclient.Switchclient.main(Switchclient.java:21)
Caused by: java.lang.ClassNotFoundException: javax.websocket.ContainerProvider
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 1 more

[root@cet7 ~]# java -version
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)

我又查了一下,发现“ContainerProvider的容器实现的全限定类名必须列在META-INF/services/javax.websocket.ContainerProvider文件中根据 Oracle 文档,ServiceLoader API 的实现 JAR 文件。因此,我将 serviceloader-maven-plugin 添加到 pom.xml。结果是它确实生成了META-INF/services/javax.websocket.ContainerProvider文件,但是没有任何内容,并且运行时错误继续存在。我尝试手动修改下面的内容并将其重新打包到 JAR 中,但没有成功:

    org.glassfish.tyrus.container.inmemory.InMemoryContainerProvider org.glassfish.tyrus.client.ClientManager

我已附上 Java 文件和 pom.xml。我已经工作了几个小时,但不知道问题是什么,所以对这个线程的任何回复将不胜感激。

非常感谢。

===========LIST1:pom.xml===========

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.sample</groupId>
    <artifactId>Switchclient</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <archive>
            <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>org.sample.switchclient.Switchclient</mainClass>
            </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>eu.somatik.serviceloader-maven-plugin</groupId>
                <artifactId>serviceloader-maven-plugin</artifactId>
                <version>1.0.6</version>
                <configuration>
                    <services>
                        <param>javax.websocket.ContainerProvider</param>
                    </services>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.glassfish.tyrus.bundles</groupId>
            <artifactId>tyrus-standalone-client-jdk</artifactId>
            <version>1.12</version>
        </dependency>
    </dependencies>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>


</project>

===========LIST2: Switchclient.java=========== 包org.sample.switchclient;

import java.net.URI;
import javax.websocket.ClientEndpoint;
import javax.websocket.ContainerProvider;
import javax.websocket.OnMessage;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;

@ClientEndpoint
public class Switchclient 
    @OnMessage
    public void onRemoteMessage (String message) 
        System.out.println("Received msg: "+message); 
    

    public static void main(String[] args) 
        WebSocketContainer container = null;
        Session session = null;
        try
            container = ContainerProvider.getWebSocketContainer();
            session = container.connectToServer (Switchclient.class, URI.create("ws://localhost:8080/Switchserver/"));
        catch (Exception e) 
            e.printStackTrace();
        
    

【问题讨论】:

【参考方案1】:

基本上,Tyrus 需要 Java EE。这就是你必须在pom.xml 中列出很多依赖项的原因。如果您使用 Java SE 并希望保持项目较小,请使用另一个仅依赖于 Java SE 的不同 WebSocket 客户端库。例如,nv-websocket-client(我的)。

只需将以下依赖添加到pom.xml

<dependency>
    <groupId>com.neovisionaries</groupId>
    <artifactId>nv-websocket-client</artifactId>
    <version>1.13</version>
</dependency>

然后试试:

import com.neovisionaries.ws.client.*;

public class Switchclient

    public static void main(String[] args) throws Exception
    
        WebSocket websocket = new WebSocketFactory()
            .createSocket("ws://localhost:8080/Switchserver/")
            .addListener(new WebSocketAdapter() 
                @Override
                public void onTextMessage(WebSocket ws, String message) 
                    System.out.println("Received msg: " + message);
                
            )
            .connect();

        // Don't forget to call disconnect() after use.
        // websocket.disconnect();
    

【讨论】:

谢谢Takahiko,很抱歉很晚才回复。我原以为我应该先验证这种方式,然后再回复;但事实证明,一旦我使用 Tyrus 方式,我就会专注于许多其他方面。但是最好有 nv-websocket-client 解决方案,因为它只依赖于 Java SE。我很快就会转移到这个解决方案。再次感谢,新年快乐 ;-) 再次感谢 Takahiko,因为我测试了这个客户端库到目前为止工作正常;-) 嗨,我是 java 新手,我使用 .net。 Tyrus 需要 Java EE。您能否提供更多信息或详细说明哪个组件是 Java EE 的一部分? @gfan javax.websocket 包包括 WebSocket 的类。规范定义为JSR 356: Java API for WebSocket。 真的太棒了...可惜我在尝试了其他一些方法后找到了它【参考方案2】:

我不确定究竟是什么导致了这个问题,因为我一直在尝试,并且在过去的一天中问题不断出现。但最后是它: 客户端依赖:

        <dependency>
        <groupId>javax.websocket</groupId>
        <artifactId>javax.websocket-client-api</artifactId>
        <version>1.1</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.tyrus.bundles</groupId>
        <artifactId>tyrus-standalone-client</artifactId>
        <version>1.12</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.tyrus</groupId>
        <artifactId>tyrus-container-grizzly-client</artifactId>
        <version>1.12</version>
    </dependency>

乍一看似乎 javax.websocket-client-api 应该足够了,但最后网络说 ContainerProvider 没有障碍。 然后,一切建好。 (与我原来的帖子不同的java代码,我尝试了很多包括源代码,但代码本身并不重要,而 environment 设置很重要。它们主要基于示例Tyrus 1.9 user guide 然而。)

并且通过 maven 从 NetBeans 运行是可以的,但是当我去使用“java -jar Switchclient.jar”时,同样/类似的问题跳出来说“端点”的问题。

最后(作为最后一次尝试)我将类路径中包含的所有 tar 文件(witch 由 maven-jar-plugin 通过指定“&lt;addClasspath&gt;true&lt;addClasspath&gt;”生成)复制到一个目录中,并将生成的 jar 文件复制到,然后它起作用了:[root@cet7 需要的罐子]# ls grizzly-framework-2.3.22.jar tyrus-client-1.12.jar grizzly-http-2.3.22.jar tyrus-container-grizzly-client-1.12.jar grizzly-http-server-2.3.22.jar tyrus-core-1.12.jar javax.websocket-api-1.1.jar tyrus-spi-1.12.jar javax.websocket-client-api-1.1.jar tyrus-standalone-client-1.12.jar Switchclient-1.1-SNAPSHOT.jar [root@cet7 requiredjars]# java -jar Switchclient-1.1-SNAPSHOT.jar 收到的消息:Hello world

就是这样,肮脏但有效。我正处于一个新的开始。再说一次,我真的是 java 新手(那些非硬技术人员之一,在需要时拿起它);它向我展示了基于社区的开发的共谋,尤其是在技术相对较新的情况下。依赖和陷阱无处不在。我猜这是自然的一部分......

【讨论】:

以上是关于ContainerProvider 的独立 Java Websocket 客户端 NoClassDefFoundError的主要内容,如果未能解决你的问题,请参考以下文章

Java笔记 - 线程基础知识

Java笔记 - 线程基础知识

JavaScript 学习

JavaScript

在 Java EE 中使用特定 IP 发送 WebSocket 请求

C++项目