Container-Agnostic Websocket抛出带有嵌入式Jetty的NPE

时间:2016-09-11 20:22:46

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

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

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

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

代码进入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();

1 个答案:

答案 0 :(得分:2)

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);