2016-09-11 49 views
1

我正在寫一個容器不可知的Websocket服務器。我的開發環境使用帶有嵌入式Jetty版本9.3.11.v20160721的IntelliJ IDEA(嵌入代碼如下)。容器不可知的Websocket拋出嵌入式碼頭的NPE

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

我想將WebSocket EndPoint註冊爲ServletContextListener。下面是Tyrus project的一些示例,以及Joakim Erdfelt(@ joakim-erdfelt)在SO和Jetty郵件列表中的一些答案,我編寫了以下實現並通過listenerweb.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(); 

回答

2

的JSR ServerContainer未在嵌入式碼頭自動初始化。

使用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); 
+0

謝謝你的提示答案。因此,澄清,這是嚴格的嵌入問題,不應該發生在部署到標準Servlet容器時,是否正確? – isapir

+0

添加該行將提前引發另一個NPE:'線程中的異常「main」java.lang.NullPointerException 與目標虛擬機斷開連接,地址:'127.0.0.1:50113',傳輸:'套接字' \t at org.eclipse .jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer.configureContext(WebSocketServerContainerInitializer。java:100)' – isapir

+0

我更新了你的答案。必須在'server.setHandler(webapp)'之後移動這條線並且修復了兩個NPE。謝謝! – isapir