与容器无关的Websocket引发带有嵌入式Jetty的NPE [英] Container-Agnostic Websocket throws NPE with Embedded Jetty
问题描述
我正在编写与容器无关的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-api
和tomcat-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.tempdir
,org.eclipse.jetty.util.DecoratedObjectFactory
,org.eclipse.jetty.tlds
,org.eclipse.jetty.resources
,org.eclipse.jetty.server.Executor
,org.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();
注意:WebSocketServerContainerInitializer
是javax.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屋!