与容器无关的Websocket引发带有嵌入式Jetty的NPE [英] Container-Agnostic Websocket throws NPE with Embedded Jetty

查看:136
本文介绍了与容器无关的Websocket引发带有嵌入式Jetty的NPE的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm writing a container-agnostic Websocket server. My development environment uses IntelliJ IDEA with an embedded Jetty version 9.3.11.v20160721 (embed code below).

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

My code, however, uses the Tomcat Websocket libraries, tomcat-websocket-api and tomcat-websocket, version 8.5.4.

我想用ServletContextListener注册Websocket EndPoint.以下是 Tyrus项目中的一些示例,以及关于SO的一些答案在Joakim Erdfelt(@ joakim-erdfelt)的Jetty邮件列表中,我编写了以下实现,并通过web.xml中的web.xml将其添加.

I want to register the Websocket EndPoint with a ServletContextListener. Following some examples from the Tyrus project, as well as some answers on SO and in the Jetty mailing list by Joakim Erdfelt (@joakim-erdfelt), I wrote the following implementation and added it via a listener in web.xml.

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

The code enters the contextInitialized() method so that part seems to work properly, but unfortunately the ServletContext does not contain the attribute javax.websocket.server.ServerContainer and therefore it returns 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

The only available attributes are javax.servlet.context.tempdir, org.eclipse.jetty.util.DecoratedObjectFactory, org.eclipse.jetty.tlds, org.eclipse.jetty.resources, org.eclipse.jetty.server.Executor, org.eclipse.jetty.webFragments

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

What am I doing wrong? Is this strictly an embedding-issue? Will it run properly in standard Jetty (i.e., not embedded)?

嵌入代码如下:

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

推荐答案

JSR ServerContainer不会在嵌入式码头中自动初始化.

The JSR ServerContainer isn't initialized automatically in 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.

Note: The WebSocketServerContainerInitializer is a javax.servlet.ServerContainerInitializer and you could set up your embedded-jetty to execute that ServerContainerInitializer automatically.

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

If you heavily rely on bytecode scanning of annotations, or have a javax.websocket.server.ServerApplicationConfig implementation, then you'll want to have the ServerContainerInitializer execute automatically.

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

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

If you use the org.eclipse.jetty.servlet.ServletContextHandler (the more common form in embedded-jetty) then you cannot use a javax.servlet.ServerContainerInitializer.

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

To set that up, do this:

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

这篇关于与容器无关的Websocket引发带有嵌入式Jetty的NPE的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆