【问题标题】:Integrating JSR-356 WebSocket @ServerEndpoint with Spring 3 beans将 JSR-356 WebSocket @ServerEndpoint 与 Spring 3 bean 集成
【发布时间】:2014-03-16 10:20:32
【问题描述】:

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

我想在我的@ServerEndpoint WebSocket 服务器中有单例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 但用户连接):

【问题讨论】:

    标签: java spring websocket spring-3 jsr356


    【解决方案1】:

    您可以使用 spring framework 3.x 设置 websockets

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

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

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

    Endpoint 注册是由 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 上查看完整的源代码并准备运行示例。

    【讨论】:

    • 很好的例子!作为一种好的做法,我也会在 try catch 中包含对 (ServerContainer) 的强制转换。我(懒惰地)复制了您的 sn-p 并且由于依赖问题而在 Tomcat 上部署时出现了完全静默的类转换异常。我花了几个小时才找到问题。
    • 你能帮忙检查一下我在 github 上的问题吗?此代码中可能存在错误
    【解决方案2】:

    试试

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

    并添加maven依赖

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

    【讨论】:

    • spring-websocket 是 post 4.0,而不是 spring 3。
    【解决方案3】:

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

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

    这样@Autowired 注释将正确工作:

    @Autowired MyService myService;
    

    【讨论】:

      【解决方案4】:

      试试这个,它对我有用

      @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 并覆盖该方法将是一种解决方法。 我认为最好用 spring-websocket 和消息传递 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);
          }
      }
      

      【讨论】:

      • 不知道以后会不会有更多的bug。
      【解决方案5】:

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

      我发现集成 JSR 356 websocket @ServerEndpoint 的解决方案是通过 spring 关闭 Servlet 容器对 WebSocket 端点的扫描,这可以通过在 Spring 配置中注册 @Bean 来完成。到这个春天,spring STOMP websocket 不会覆盖普通的 JSR 356 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();
        }
      }
      

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

      如果你没问题,那么请关注这个Link 来了解概念。

      请注意,通常您应该将 websocket 配置与 spring 的主要配置分开。

      【讨论】:

        猜你喜欢
        • 2016-03-18
        • 1970-01-01
        • 1970-01-01
        • 2014-11-04
        • 1970-01-01
        • 2013-10-13
        • 2014-03-20
        • 2015-05-26
        • 2014-10-12
        相关资源
        最近更新 更多