在嵌入式码头上向Websocket端点注入依赖项

问题描述

我有以下websocket端点:

import javax.inject.Inject;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint(value = "/blabla")
public class WebsocketService {

    @Inject
    private DatabaseProvider dbProvider;

    @Onopen
    public void onopen(Session session) throws IOException {
        //do something
    }

    @OnMessage
    public void onMessage(Session session,String socketPacket) throws IOException {
        //do something else
    }
    ...
}

启动嵌入式服务器的代码

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
import javax.websocket.server.ServerContainer;
//other imports

public static void main(String[] args) {
    Server server = null;
    try {
        server = new Server(3081);
        ServletContextHandler context = new ServletContextHandler();
        context.setcontextpath("/");
        ServerContainer serverContainer = WebSocketServerContainerInitializer.configureContext(context);
        serverContainer.addEndpoint(WebsocketService.class);
        server.setHandler(context);
        server.start();
        server.join();
    } catch (Exception e) {
        logger.error(e.getMessage());
    } finally {
        if (server != null) {
            server.destroy();
        }
    }
}

上面的代码非常适合没有依赖项注入的情况。但是,我想将 dbProvider 注入我的WebsocketService中,并在 onMessage 方法中使用它。

问题1:如何为websocket服务器进行注入?

P.S。有多个示例说明如何使用ResourceConfig + AbstractBinder + ServletContainer对REST端点进行依赖注入,但是我不确定如何将其应用于websocket服务器。

问题2:如何将简单的资源终结点添加到同一服务器(以提供javascript)?

解决方法

这个问题中有很多活动内容。

首先,您必须设置Weld(CDI实现)以使其与ServletContextHandler

正确集成

通常这样看...

ServletContextHandler context = new ServletContextHandler();
// Enable Weld + CDI
context.setInitParameter(
  CdiServletContainerInitializer.CDI_INTEGRATION_ATTRIBUTE,CdiDecoratingListener.MODE);
context.addBean(
  new ServletContextHandler.Initializer(context,new CdiServletContainerInitializer()));
context.addBean(
  new ServletContextHandler.Initializer(context,new org.jboss.weld.environment.servlet.EnhancedListener()));

然后在Jetty和Weld之间自动进行内部注射(实际上是装饰)。

注意: ServletContexthandler.Initializer是一个便利类,它使嵌入式码头可以运行任意javax.servlet.ServletContainerInitializer,而无需使用功能强大的WebApp的所有开销,而且它很复杂初始化过程。

  • CdiServletContainerInitializer是Jetty提供的ServletContainerInitializer,它在ServletContext中进行了各种设置,以使Weld能够正确地将自身连接到ServletContext
  • EnhancedListener也是焊接提供的ServletContainerInitializer,它是焊接+ CDI接线的一面。

要提供静态文件,您需要在ServletContextHandler中定义一个“基础资源”,然后将DefaultServlet添加到"/"的“默认” URL模式中

ServletContextHandler context = new ServletContextHandler();
context.setBaseResource(Resource.newResource(webRootUri));
context.addServlet(DefaultServlet.class,"/");

如果您想同时查看所有这些内容,请在以下位置查看示例项目

https://github.com/jetty-project/embedded-jetty-weld