与容器无关的 Websocket 使用嵌入式 Jetty 抛出 NPE
Container-Agnostic Websocket throws NPE with Embedded Jetty
我正在编写一个与容器无关的 Websocket 服务器。我的开发环境使用带有嵌入式 Jetty 版本的 IntelliJ IDEA 9.3.11.v20160721
(下面嵌入代码)。
但是,我的代码使用 Tomcat Websocket 库,tomcat-websocket-api
和 tomcat-websocket
,版本 8.5.4
。
我想用 ServletContextListener
注册 Websocket EndPoint
。根据 Tyrus project 中的一些示例,以及 Joakim Erdfelt (@joakim-erdfelt) 在 SO 和 Jetty 邮件列表中的一些答案,我编写了以下实现并通过 listener
添加了它web.xml
.
代码进入 contextInitialized()
方法,因此该部分似乎可以正常工作,但不幸的是,ServletContext 不包含属性 javax.websocket.server.ServerContainer
,因此它 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
我做错了什么?这严格来说是一个嵌入问题吗?它会在标准 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();
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();
注意:WebSocketServerContainerInitializer
是一个 javax.servlet.ServerContainerInitializer
,您可以将 embedded-jetty
设置为自动执行 ServerContainerInitializer
。
如果您严重依赖注释的字节码扫描,或者有一个 javax.websocket.server.ServerApplicationConfig
实现,那么您会希望 ServerContainerInitializer
自动执行。
Note: the javax.servlet.ServerContainerInitializer
is only valid for a org.eclipse.jetty.webapp.WebAppContext
.
If you use the org.eclipse.jetty.servlet.ServletContextHandler
(the more common form in embedded-jetty) then you cannot use a 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);
我正在编写一个与容器无关的 Websocket 服务器。我的开发环境使用带有嵌入式 Jetty 版本的 IntelliJ IDEA 9.3.11.v20160721
(下面嵌入代码)。
但是,我的代码使用 Tomcat Websocket 库,tomcat-websocket-api
和 tomcat-websocket
,版本 8.5.4
。
我想用 ServletContextListener
注册 Websocket EndPoint
。根据 Tyrus project 中的一些示例,以及 Joakim Erdfelt (@joakim-erdfelt) 在 SO 和 Jetty 邮件列表中的一些答案,我编写了以下实现并通过 listener
添加了它web.xml
.
代码进入 contextInitialized()
方法,因此该部分似乎可以正常工作,但不幸的是,ServletContext 不包含属性 javax.websocket.server.ServerContainer
,因此它 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
我做错了什么?这严格来说是一个嵌入问题吗?它会在标准 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();
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();
注意:WebSocketServerContainerInitializer
是一个 javax.servlet.ServerContainerInitializer
,您可以将 embedded-jetty
设置为自动执行 ServerContainerInitializer
。
如果您严重依赖注释的字节码扫描,或者有一个 javax.websocket.server.ServerApplicationConfig
实现,那么您会希望 ServerContainerInitializer
自动执行。
Note: the
javax.servlet.ServerContainerInitializer
is only valid for aorg.eclipse.jetty.webapp.WebAppContext
.If you use the
org.eclipse.jetty.servlet.ServletContextHandler
(the more common form in embedded-jetty) then you cannot use ajavax.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);