Jetty 中的 JSR-356 javax websockets(嵌入式和非嵌入式)
Posted
技术标签:
【中文标题】Jetty 中的 JSR-356 javax websockets(嵌入式和非嵌入式)【英文标题】:JSR-356 javax websockets in Jetty (embedded and not) 【发布时间】:2018-11-28 06:09:05 【问题描述】:鉴于:
我想将 webapp(打包为 WAR,其中包含 web.xml
)部署到 Jetty 服务器。
在该应用程序中,我希望能够配置 JSR-356 指定的 javax websocket 端点。我更喜欢那些通过ServerEndpointConfig
提供的端点,不是注释扫描。
有许多资源可以通过嵌入式 Jetty 来举例说明,这些资源利用了众所周知的 WebSocketServerContainerInitializer.configureContext(context);
API。很明显,我做不到。
还有其他的,直接跳转到ServletContextListener
,通过著名的context.getAttribute("javax.websocket.server.ServerContainer"
获得ServerContainer
)。到目前为止,我通过这个 API 得到了很多 NULL
,所以显然没有添加容器。
问题:
缺少的配置是什么?可以通过web.xml
完成吗?如果它是关于像 jetty.xml
或 jetty.ini
这样的配置文件 - 再一次的例子会很好,最好是 xml
语法。
更新:
根据下面的答案(已接受的答案)以及我实际上试图在这里描述的那样 - 已知的配置方式绝对工作得很好。说已知我的意思是通过将--module=websocket
添加到某个非嵌入式码头的*.ini
文件,或者通过调用WebSocketServerContainerInitializer.configureContext
来获取嵌入式码头。
所以换个说法:有人有任何经验/知识可以通过纯粹基于XML
的配置来启用 websocket 模块吗?
【问题讨论】:
【参考方案1】:如果使用$jetty.base
和$jetty.home
recommended installation process for Standalone Jetty,您应该转到您的$jetty.base
实例目录并启用websocket
模块。
$ cd /path/to/mybase
$ java -jar /opt/jetty/jetty-home-9.4.14.v20181114/start.jar --add-to-start=websocket
$ grep "websocket" start.ini
--module=websocket
现在您已经为 $jetty.base
实例启用了 websocket。
如果您希望 Jetty 通过字节码扫描您部署的 web 应用以查找注释来发现您的服务器 WebSocket 端点,那么您还需要 annotations
模块。
$ cd /path/to/mybase
$ java -jar /opt/jetty/jetty-home-9.4.14.v20181114/start.jar --add-to-start=annotations
$ grep "annotations" start.ini
--module=annotations
完成后,您可以执行以下一项(或多项)操作以将 websocket 服务器端点与您的 web 应用程序一起部署。
只需使用@ServerEndpoint
(来自javax.websocket.server.ServerEndpoint
)注释您的类
或者,如果您想以编程方式添加 WebSocket 服务器端点,您有 2 个选项。
-
在您的项目中提供
javax.websocket.server.ServerApplicationConfig
的实现,并返回您希望 Jetty 部署的服务器端点。
在 WebApp 启动/初始化期间,从 ServletContext.getAttribute("javax.websocket.server.ServerContainer")
获取 javax.websocket.server.ServerContainer
并使用它的 addEndpoint()
方法。请注意,这仅适用于 ServletContextListener.contextInitialized(ServletContextEvent sce)
或 ServletContainerInitializer.onStartup(Set<Class<?>> c, ServletContext ctx)
为什么这在独立的 Jetty 中有效?独立的 Jetty 做了什么来使这成为可能?
会发生以下情况:
websocket
module 将lib/websocket/*.jar
添加到服务器类路径
websocket
模块依赖于 client
和 annotations
模块
client
module 将lib/jetty-client-<jetty.version>.jar
添加到服务器类路径
annotations
module 将lib/jetty-annotations-<jetty.version>.jar
和lib/annotations/*.jar
添加到服务器类路径中
annotations
模块依赖于plus
模块
annotations
模块选择 etc/jetty-annotations.xml
在启动时执行
annotations
模块按名称添加 JPMS 模块org.objectweb.asm
plus
module 将lib/jetty-plus-<jetty.version>.jar
添加到服务器类路径
plus
模块选择 etc/jetty-plus.xml
在启动时执行
plus
模块依赖于 server
、security
、jndi
、webapp
和 transactions
模块
(我将跳过以这种方式选择的其余模块)
简而言之,只需添加 websocket
模块,您就可以获得以下服务器类路径条目
lib/websocket/*.jar
lib/jetty-client-<jetty.version>.jar
lib/jetty-annotations-<jetty.version>.jar
lib/annotations/*.jar
lib/jetty-plus-<jetty.version>.jar
以及以下 XML 文件
lib/jetty-annotations.xml
lib/jetty-plus.xml
这两个 XML 文件都只是修改了服务器端的默认 Configuration
列表,使它们引入的 Configuration
行为可用于所有已部署的 WebApp。
您也可以set the Configuration
on the WebAppContext
(在它开始之前)针对 web 应用的特定行为。
例子:
WebAppContext context = new WebAppContext();
context.setContextPath("/");
context.setBaseResource(Resource.newResource(rootResourceUrl));
context.setConfigurations(new Configuration[]
new AnnotationConfiguration(),
new WebXmlConfiguration(),
new WebInfConfiguration(),
new PlusConfiguration(),
new MetaInfConfiguration(),
new FragmentConfiguration(),
new EnvConfiguration());
handlerList.addHandler(context);
注意:对于
javax.websocket
,您必须使用WebAppContext
,因为为其初始化定义的行为需要完整的Web 应用程序才能运行。 虽然您可以将ServletContextHandler
与javax.websocket
端点一起使用,但这种样式是 100% 手动定义、初始化和声明的,没有 JSR-356 依赖的自动字节码/注释扫描功能。
您也可以从命令行查看所有这些内容。
显示活动的$jetty.base
配置,XML 属性值是什么,服务器类路径是什么,以及将执行什么 XML(以及以什么顺序!!)
$ cd /path/to/mybase
$ java -jar /opt/jetty/jetty-home-9.4.14.v20181114/start.jar --list-config
显示模块列表以及它们之间的关系(以及在您的$jetty.base
配置中选择的模块)
$ cd /path/to/mybase
$ java -jar /opt/jetty/jetty-home-9.4.14.v20181114/start.jar --list-modules
【讨论】:
正如我在问题中所述,您在此处概述的路径对我来说是已知的并且正在工作(--module=websocket
和 WebSocketServerContainerInitializer.configureContext(context)
的一些味道。太糟糕了我的情况更困难:在历史上,我部署了 embedded Jetty 从 Java 配置为读取 XML 文件并由它们配置。对此有什么建议吗?
“模块”是 Jetty 9.x 中一个纯粹独立的 Jetty 概念。 Jetty 10.x 中引入了嵌入式码头的“模块”,但作为正式的 JPMS 模块。
感谢您对看似不可能的事情的认可(Jetty 9.4..)。好吧,看起来我要放弃 JAVAX 方式并使用 WebSockets 'Jetty' 方式(servlet 等)。
如果您愿意,您仍然可以执行inferior javax way,您只需在为您的 JSR-356 (javax.websocket
) 行为启动 WebAppContext
之前声明服务器 Configuration
。注意:您必须使用WebAppContext
,而不是ServletContextHandler
。以上是关于Jetty 中的 JSR-356 javax websockets(嵌入式和非嵌入式)的主要内容,如果未能解决你的问题,请参考以下文章
带有 Spring Boot 的 JAVAX JSR 356 Websocket
尝试使用 jsr 356 时出现 java.lang.linkage 错误