将JSR-356 WebSocket @ServerEndpoint与Spring 3 bean集成

时间:2014-03-16 10:20:32

标签: java spring websocket spring-3 jsr356

我使用Spring 3.2.5而没有全新的JSR-356 WebSockets支持。

我想在我的@ServerEndpoint WebSocket服务器中使用singleton-bean引用,该服务器由servlet容器本身实例化,而不是在Spring上下文中。

干净的方法是什么?

我当前的解决方案:我在静态字段中使用实例制作了@Service单例bean:

@Service
public class WebSocketSupportBean {
    private volatile static WebSocketSupportBean instance = null;

    public static WebSocketSupportBean getInstance() {
        return instance;
    }

    public WebSocketSupportBean() {
        instance = this;
    }

并通过静态方法在@ServerEndpoint中获取它,如果返回null则断开用户连接(如果在服务器启动期间未创建bean但是用户连接):

5 个答案:

答案 0 :(得分:7)

您可以使用spring framework 3.x

设置websockets

我开发了一个小概念验证应用程序来演示如何基于Rossen Stoyanchev的SpringConfiguration与spring-core 4.0一起发布。

应用程序使用uri /wstest设置websocket服务器端点,该端点将使用@Autowired spring bean来选择问候语并回复websocket消息。

启动websocket连接,并在支持websockets的浏览器中运行的html页面(index.html)发送消息。

在上下文初始化时,ServletContextListener进行端点注册,当实例化端点时,它将与spring连接:

@WebListener
public class MyApplication implements ServletContextListener {

    private final static String SERVER_CONTAINER_ATTRIBUTE = "javax.websocket.server.ServerContainer";

    @Override
    public void contextInitialized(ServletContextEvent sce) {

        ServletContext container = sce.getServletContext();

        final ServerContainer serverContainer = (ServerContainer) container.getAttribute(SERVER_CONTAINER_ATTRIBUTE);
        try {
            serverContainer.addEndpoint(new MyEndpointConfig(MyEndpoint.class, "/wstest"));
        } catch (DeploymentException e) {
            e.printStackTrace();
        }
    }
}

端点是:

@Component
public class MyEndpoint extends Endpoint {

    @Autowired
    MyService myService;

    @Override
    public void onOpen(Session session, EndpointConfig config) {

        session.addMessageHandler(new MyMessageHandler(session));
    }


    class MyMessageHandler implements MessageHandler.Whole<String> {

        final Session session;

        public MyMessageHandler(Session session) {
            this.session = session;
        }

        @Override
        public void onMessage(String message) {
            try {
                String greeting = myService.getGreeting();
                session.getBasicRemote().sendText(greeting + ", got your message (" + message + "). Thanks ! (session: " + session.getId() + ")");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

在我的Github page上查看完整的来源并准备好运行示例。

答案 1 :(得分:2)

尝试

@ServerEndpoint(value = "/ws", configurator = SpringConfigurator.class)

并添加maven依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-websocket</artifactId>
</dependency>

答案 2 :(得分:1)

您可以使@ServerEndpoint对象扩展SpringBeanAutowiringSupport。然后让它知道以这种方式在基于Spring的Web应用程序中构造的bean:

  @PostConstruct
    public void init() {
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
    }

这样@Autowired注释将正确运行:

@Autowired MyService myService;

答案 3 :(得分:1)

试试这个,它对我有用

@Component
@ServerEndpoint(value = "/instantMessageServer",configurator = SpringConfigurator.class)
public class InstantMessageServer{
private static IChatService chatService;
    @Autowired
    public InstantMessageServer(IChatService chatService){
        this.chatService = chatService;
    }
    public InstantMessageServer(){}
}

我在https://spring.io/blog/2013/05/23/spring-framework-4-0-m1-websocket-support找到了这个解决方案 但是还有一个小问题,用@ServerEndpoint注释的类不能用SpringConfigurator获取httpsession,在它中没有方法modifyhandler的覆盖。也许我们创建一个单独的Configurator扩展SpringConfigurator并覆盖该方法将是一个workaroud。 我认为最好使用spring-websocket和messaging api构建一个实时Web应用程序。

public class ModifiedServerEndpointConfigurator extends SpringConfigurator{
    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        HttpSession httpSession = (HttpSession) request.getHttpSession();
        sec.getUserProperties().put(HttpSession.class.getName(),httpSession);
        super.modifyHandshake(sec, request, response);
    }
}

答案 4 :(得分:1)

您必须在spring的配置中添加bean定义。

我发现集成JSR 356 websocket @ServerEndpoint的解决方案是在spring之前关闭Servlet容器对WebSocket端点的扫描,这可以通过在Spring Configuration中注册@Bean来完成。到这个弹簧,弹簧STOMP Websocket不会取代普通的JSR 356 Websocket,而STOMP Websocket是Websocket的一部分。

@ServerEndpoint(value="/chatMessage")
public class ChatEndpoint{
// Normal websocket body goes here.
}

在配置中添加Bean的方式为:

@Configuration
public class WebsocketConfig{
  @Bean
  public ChatEndpoint chatEndpoint(){
     return new ChatEndpoint();
  }
  // main one is ServerEndpointExporter which prevents Servlet container's scan for WebSocket
  @Bean
  public ServerEndpointExporter endpointExporter(){
     return new ServerEndpointExporter();
  }
}

这一切都为您完成。但是您应该从configurator = SpringConfigurator.class中删除@ServerEndpoint。 我正在使用Spring Websocket 4.0.0,它工作正常。 您还可以看到此Link

如果您还可以的话,也请遵循此Link的概念。

请注意,通常,您应该将Websocket配置与Spring的主要配置分开进行。