【问题标题】:Container-Agnostic Websocket throws NPE with Embedded Jetty与容器无关的 Websocket 使用 Embedded Jetty 抛出 NPE
【发布时间】:2017-01-19 07:12:03
【问题描述】:

我正在编写一个与容器无关的 Websocket 服务器。我的开发环境使用带有嵌入式 Jetty 版本的 IntelliJ IDEA 9.3.11.v20160721(嵌入代码如下)。

然而,我的代码使用 Tomcat Websocket 库,tomcat-websocket-apitomcat-websocket,版本 8.5.4

我想用ServletContextListener 注册Websocket EndPoint。根据Tyrus project 的一些示例,以及关于SO 和Joakim Erdfelt (@joakim-erdfelt) 的Jetty 邮件列表中的一些答案,我编写了以下实现并通过listener 中的listener 添加它。

代码进入contextInitialized()方法,所以该部分似乎工作正常,但不幸的是ServletContext不包含属性javax.websocket.server.ServerContainer,因此它返回null。

@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {

    final ServerContainer serverContainer = (ServerContainer) servletContextEvent
            .getServletContext()
            .getAttribute("javax.websocket.server.ServerContainer");

    // *** serverContainer is null ***

    try {
        serverContainer.addEndpoint(ChatAnnotation.class);
    } 
    catch (DeploymentException e) { e.printStackTrace(); }
}

唯一可用的属性是javax.servlet.context.tempdirorg.eclipse.jetty.util.DecoratedObjectFactoryorg.eclipse.jetty.tldsorg.eclipse.jetty.resourcesorg.eclipse.jetty.server.Executororg.eclipse.jetty.webFragments

我做错了什么?这严格来说是一个嵌入问题吗?它会在标准 Jetty 中正常运行(即未嵌入)吗?

嵌入代码如下:

WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/");
webapp.setResourceBase(webroot);   
webapp.setDescriptor(webroot + "/WEB-INF/web.xml");

Server server = new Server();

ServerConnector connector = new ServerConnector(server);
connector.setPort(8080);             

server.setConnectors(new ServerConnector[] { connector });
server.setHandler(webapp);      
server.start();
server.join();

【问题讨论】:

    标签: servlets websocket jetty embedded-jetty java-websocket


    【解决方案1】:

    JSR ServerContainer 不会在 Embedded-jetty 中自动初始化。

    使用WebSocketServerContainerInitializer ...

    WebAppContext webapp = new WebAppContext();
    webapp.setContextPath("/");
    webapp.setResourceBase(webroot);   
    webapp.setDescriptor(webroot + "/WEB-INF/web.xml");
    
    Server server = new Server();
    
    ServerConnector connector = new ServerConnector(server);
    connector.setPort(8080);             
    
    server.setConnectors(new ServerConnector[] { connector });
    server.setHandler(webapp);
    
    // Add this line
    WebSocketServerContainerInitializer.configureContext(webapp);
    
    server.start();
    server.join();
    

    注意:WebSocketServerContainerInitializerjavax.servlet.ServerContainerInitializer,您可以设置您的 embedded-jetty 以自动执行 ServerContainerInitializer

    如果您严重依赖注释的字节码扫描,或者有javax.websocket.server.ServerApplicationConfig 实现,那么您会希望ServerContainerInitializer 自动执行。

    注意:javax.servlet.ServerContainerInitializer 仅对 org.eclipse.jetty.webapp.WebAppContext 有效。

    如果您使用org.eclipse.jetty.servlet.ServletContextHandler(嵌入式码头中更常见的形式),则不能使用javax.servlet.ServerContainerInitializer

    要设置它,请执行以下操作:

    private void enableAnnotationScanning(Server server)
    {
        Configuration.ClassList classlist = Configuration.ClassList.setServerDefault(server);
        classlist.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration",
                "org.eclipse.jetty.plus.webapp.EnvConfiguration",
                "org.eclipse.jetty.plus.webapp.PlusConfiguration");
        classlist.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
                "org.eclipse.jetty.annotations.AnnotationConfiguration");
    }
    
    // ... later on ...
    
    Server server = new Server();
    enableAnnotationScanning(server);
    

    【讨论】:

    • 感谢您的及时答复。所以澄清一下,这严格来说是一个嵌入问题,在部署到标准 Servlet 容器时不应该发生,对吗?
    • 添加该行会在早期引发另一个 NPE:Exception in thread "main" java.lang.NullPointerException Disconnected from the target VM, address: '127.0.0.1:50113', transport: 'socket' at org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer.configureContext(WebSocketServerContainerInitializer.java:100)
    • 我更新了你的答案。在server.setHandler(webapp) 之后不得不将线路向下移动,这修复了两个 NPE。谢谢!
    • 只要您在jetty-distribution 中启用了--module=websocket,它就可以在不需要额外的行的情况下工作。
    • 我实际上尽量避免扫描,因为它们会增加启动时间的长时间延迟。嵌入式 Jetty 主要用于开发目的,因此添加该行不是问题。我正在争论是否在这个项目中使用Jetty-WebsocketTomcat-Websocket,并且Tomcat 的依赖项似乎更“有条理”(我可能是错的),所以至少目前我选择了Tomcat。我可能会改用 Jetty,因为你们在这里提供了很好的支持。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-16
    • 2018-10-21
    • 2015-06-13
    • 1970-01-01
    • 1970-01-01
    • 2018-01-02
    • 2023-03-06
    相关资源
    最近更新 更多