集成CDI和WebSockets

考虑尝试一个简单的Java EE 7原型应用程序,该应用程序涉及JAX-RS(REST),WebSockets和CDI。

注意 :不想让它成为破坏者-但这篇文章主要讨论了我在尝试使用Web套接字和使用CDI作为“胶水”的REST(在Java EE应用程序中)时遇到的问题。 整合并未实现,但是仍然吸取了一些教训:-)

这个想法是使用REST端点作为Web套接字端点的“提要”,从而将数据“推”到所有连接的客户端:

  • JAX-RS端点,它从其他来源接收数据(可能是实时的)作为Web套接字端点的输入
  • 使用CDI事件作为黑白JAX-RS和WebSocket端点的粘合剂,并“触发”有效负载
    @Path("/feed")
    public class RESTFeed {
    
        @Inject
        Event<String> event;
    
        @POST
        @Consumes(MediaType.TEXT_PLAIN)
        public void push(String msg) {
            event.fire(msg);
        }
    }
  • 在WebSocket端点实现中使用CDI Observer方法将数据推送到连接的客户端:
    public void onMsg(@Observes String msg) {
    
            //different WS enpoint instance - notice the hash code value in the server log
            System.out.println("WS End point class ID -- " + this.hashCode());
            try {
    
                client.getBasicRemote().sendText(msg);
    
            } catch (IOException ex) {
                Logger.getLogger(ServerEndpoint.class.getName()).log(Level.SEVERE, null, ex);
            }
    }

当然,目前还没有考虑到更详细的信息,例如性能,异步通信等。 更多实验

但这有可能吗?

这是我执行的步骤

开始

  • 使用Postman在REST端点上触发HTTP POST请求

防火

繁荣! Observer方法中的NullPointerException –我等待了几秒钟,然后现实击中了我!

pe

根本原因(据我了解)

  • WebSocket端点的行为

WebSocket端点与JAX-RS资源类相似,因为每个连接的客户端都有一个Web套接字端点类的实例(至少默认情况下)。 WebSocket规范中明确提到了这一点。 客户端(对等方)连接后,便会创建一个唯一的实例,并且可以安全地将Web套接字会话对象(对等方的表示形式)作为实例变量进行缓存。 IMO,这是一个简单干净的编程模型

规格

  • 但是CDI容器还有其他计划!

REST端点一旦触发CDI事件(响应POST请求),CDI容器就会创建WebSocket终结点(在本例中为CDI Observer)的其他实例。 为什么? 因为CDI bean本质上是上下文相关的 。 该应用程序不控制CDI bean的实例。 它只是使用它们(通过@Inject)。 由容器来创建和销毁bean实例,并确保在相同上下文中执行的bean可以使用适当的实例。 容器如何确定上下文呢? 通过范围 –应用程序,会话,请求等…..

(再次,在CDI规范中明确提到)

规格

因此,问题的要点是没有WebSocket终结点当前上下文的实例–因此,CDI将创建一个新实例以传递消息。 当然,这意味着实例变量将指向null,因此将指向NPE(Duh!)

WebSocket端点将使用哪个CDI范围? 我尝试了@ ApplicationScoped,@ SessionScoped和@RequestScoped却没有太多运气–仍然是一个新实例和一个NPE

还有其他选择吗?

  • 将会话集定义为静态变量将达到目的:
    private static Set<Session> peers = Collections.synchronizedSet(new HashSet());

但是,如果仅在观察者方法中需要处理客户端特定状态(只能作为实例变量处理)的情况下,IMO只是一种黑客手段,这是不可行的–它势必会保持未初始化的状态。

  • 服务器发送事件 ? 但是最终,SSE!= WebSocket。 如果用例要求“仅”服务器端推送,则可以选择使用。 SSE尚未成为Java EE标准-Java EE 8可能使之成为可能

解决方法

我不是专家,但是我想这取决于WebSocket规范,以便更清楚地说明如何将其与CDI结合使用。 鉴于CDI是Java EE规范中必不可少的一部分,因此将其与其他规范(特别是以HTML5为中心的规范,例如JAX-RS,WebSocket等)进行无缝集成非常重要。

Bruno Borges的这篇文章链接到与JMS,CDI和WebSocket以及它们如何相互集成有关的类似问题。

我错过了明显的事情吗? 您有什么建议/解决方案吗? 请随时鸣叫! :-)

示例代码在GitHub可用 (以供您查看)。 我在GlassFish 4.1和Wildfly 8.2.0上尝试过

我想现在就这些了。 :-)

干杯!

翻译自: https://www.javacodegeeks.com/2015/02/integrating-cdi-websockets.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值