Tyrus 服务器可以使用内部类端点吗?
Posted
技术标签:
【中文标题】Tyrus 服务器可以使用内部类端点吗?【英文标题】:Can Tyrus server use inner class endpoints? 【发布时间】:2015-05-10 02:27:30 【问题描述】:我在让一个极其简单的独立 Tyrus websocket 服务器工作时遇到问题。我已经让它在对我没有意义的非常特殊的情况下工作。
正常工作的情况是我定义了一个***(在它自己的文件中)服务器端点类并使用@ServerEndpoint 对其进行注释。此类包括用@OnOpen、@OnMessage 和@OnClose 注释的方法,这些都是典型的东西。我将此类传递给 Server 构造函数。我的简单客户端可以连接到这个服务器,并成功发送消息,服务器接收到。
当我将***服务器端点类更改为初始化服务器的类的内部类时会出现问题(这是我所做的唯一更改)。在这种情况下,我的客户端可以连接并调用客户端的 @OnOpen 方法。但是服务器不会实例化服务器端点,因此它的 @OnOpen 方法永远不会被调用。显然,服务器消息接收不会发生。
Tyrus 中是否要求带注释的服务器端点类不能是内部类?如果没有,服务器端点类是否有特定权限(所有内容都已公开,试图让它正常工作)?我在 Mac、OSX 1.9.5 上使用 Tyrus 1.9 和 JDK 1.7。
简单服务器(包括并配置为使用失败的内部服务器端点):
package tyrus.example;
import java.util.concurrent.TimeUnit;
import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.glassfish.tyrus.server.Server;
public class SimpleServer
private static final String HOST_ADDR = "localhost";
private static final int HOST_PORT = 8025;
public static void main(String[] args)
Server websocketServer = new Server(HOST_ADDR, HOST_PORT, "/ws", null, InnerSimpleServerEndpoint.class);
try
websocketServer.start();
Thread.sleep(TimeUnit.MINUTES.toMillis(5));
catch (Exception e)
e.printStackTrace();
websocketServer.stop();
System.out.println("Done.");
@ServerEndpoint("/myapp")
public class InnerSimpleServerEndpoint
@OnOpen
public void onOpen(Session session)
System.out.println("Connection received for "+session.getRequestURI());
@OnMessage
public void onMessage(String message, Session session)
System.out.println("Message received: "+message);
@OnClose
public void onClose(Session session, CloseReason closeReason)
System.out.println("Session closed, reason: "+closeReason);
简单的客户端:
package tyrus.example;
import java.io.IOException;
import java.net.URI;
import javax.websocket.ClientEndpointConfig;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.Session;
import org.glassfish.tyrus.client.ClientManager;
public class SimpleClient
private static final String DEF_WS_URL = "ws://localhost:8025/ws/myapp";
public static void main(String[] args)
ClientEndpointConfig cec = ClientEndpointConfig.Builder.create().build();
ClientManager client = ClientManager.createClient();
try
client.connectToServer(new ClientEndpoint(), cec, new URI(DEF_WS_URL));
catch (Exception e)
e.printStackTrace();
System.out.println("Done.");
private static class ClientEndpoint extends Endpoint
@Override
public void onOpen(Session session, EndpointConfig config)
System.out.println("ClientEndpoint: server session opened: "+session);
session.addMessageHandler(new MessageHandler.Whole<String>()
@Override
public void onMessage(String message)
System.out.println("ClientEndpoint: received message: "+message);
);
try
session.getBasicRemote().sendText("Hello server!");
catch (IOException e)
e.printStackTrace();
最后是在服务器使用它时工作的非内部类服务器端点:
package tyrus.example;
import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint("/myapp")
public class SimpleServerEndpoint
@OnOpen
public void onOpen(Session session)
System.out.println("Connection received for "+session.getRequestURI());
@OnMessage
public void onMessage(String message, Session session)
System.out.println("Message received: "+message);
@OnClose
public void onClose(Session session, CloseReason closeReason)
System.out.println("Session closed, reason: "+closeReason);
【问题讨论】:
【参考方案1】:在服务器上,端点可以是内部类,但也必须是静态的。即使代码运行并提供服务,出于某种原因,我也只能在服务器端点也是静态的情况下使其工作。即:更改为在服务器代码中添加静态:
@ServerEndpoint("/myapp")
public static class InnerSimpleServerEndpoint
您可能还想添加
@OnError
public void onError(Session session, Throwable throwable)
//...
【讨论】:
谢谢,我遇到了同样的问题。该类必须是公共的和静态的。【参考方案2】:端点可以是内部类,但它必须是可实例化的 - 在您失败的示例中,类 ClientEndpoint
是 private
,因此 Tyrus 无法创建它的实例。
将其更改为公开,它应该可以按预期工作。
【讨论】:
Pavel 问题出在服务器上,而不是客户端。由于我的客户端代码执行端点实例化,因此客户端工作得很好。但是,如上所示,服务器正在使用内部类服务器端点InnerSimpleServerEndpoint
,它是完全公开的,包括构造函数,它失败了。然而,当使用独立类SimpleServerEndpoint
(也如上所示)时,一切正常。导致失败的内部类服务器端点是什么?我做错了什么还是 Tyrus 的错误?
啊,好吧,我评估这个问题太快了。无论如何,在这种情况下,Tyrus 不做任何事情 - 包扫描被委托给 Servlet 容器 - 请参阅 @HandlesTypes 注释 javadoc。我没有看到任何内部类的排除,所以这可能是 Servlet impl 中的一个问题(或者我根本没有正确阅读规范)。无论如何,您可以使用 javax.websocket.server API 中的 ServerApplicationConfig 类来解决此问题。
谢谢帕维尔。有没有在独立应用程序中使用ServerApplicationConfig
的示例代码?我确实玩过这个并且得到了一个空指针异常(TyrusServerConfiguration.java:191,tyrus 1.10 版)。如果您有任何内容的链接,请传递。
当然,例如这里:github.com/tyrus-project/tyrus/blob/…【参考方案3】:
内部类应该是静态的,否则如果没有外部类的实例就无法实例化。看这个: https://www.javatpoint.com/why-we-use-static-class-in-java 因此,如果使用@ServerEndpoint 注解的类不是静态的,则无法实例化。
【讨论】:
以上是关于Tyrus 服务器可以使用内部类端点吗?的主要内容,如果未能解决你的问题,请参考以下文章
尽管端点在 apicontroller 内部的行为中使用了 cors 类,但 CORS 标头未添加到响应中
我可以在 VPC 中将 SNS 订阅与内部 ALB 端点一起使用吗?