4

In a raw Spring WebSocket application (not using sockjs/STOMP or any other middleware), how can I have Spring inject beans that have been registered in the HTTP session scope so that they can be used by code in my WebSocketHandler bean?

Note that what I am not asking is any of these questions:

  • How do I create beans in a scope that is accessible to all handler invocations for the same WebSocket session (e.g. as described in the answer to Request or Session scope in Spring Websocket). The beans I need to access already exist in the scope for the HTTP session
  • How do I (programatically) access objects in the servlet container's HTTP session storage (I haven't tried to do this, but I'm pretty sure the answer involves using an HttpSessionHandshakeInterceptor), but that doesn't get me injection of Spring scoped dependencies.
  • How to use a ScopedProxy to pass beans between code in different scopes (e.g. as described here); I'm already familiar with how to do this, but attempting to do so for a WebSocketHandler causes an error because the session scope hasn't been bound to the thread at the point the object is accessed.
  • How to access the current security principal -- again, very useful, but not what I'm currently trying to achieve.

What I'm hoping to do is provide a simple framework that allows for the traditional HTTP-request initiated parts of an MVC application to communicate directly with a WebSocket protocol (for sending simple push updates to the client). What I want to be able to do is push data into a session scoped object from the MVC controller and pull it out in the websocket handler. I would like the simplest possible API for this from the MVC controller's perspective, which if it is possible to just use a session-scoped bean for this would be ideal. If you have any other ideas about very simple ways of sharing this data, I'd also like to hear those in case this approach isn't possible.

Community
  • 1
  • 1
Jules
  • 14,841
  • 9
  • 83
  • 130

1 Answers1

1

You can also use Java API for websocket. This link https://spring.io/blog/2013/05/23/spring-framework-4-0-m1-websocket-support explains how to do this with Spring. Ufortunately, something like this

@ServerEndpoint(value = "/sample", configurator = SpringConfigurator.class)
public class SampleEndpoint {

     private SessionScopedBean sessionScopedBean;

     @Autowired
      public SampleEndpoint(SessionScopedBean sessionScopedBean) {
        this.sessionScopedBean = sessionScopedBean;
      }
}

causes exception (because we're trying to access bean outside its scope), but for singleton and prototype beans it works well.

To work with session attributes you can modify the hanshake and pass required attributes:

public class CustomWebSocketConfigurator extends SpringConfigurator {
    @Override
    public void modifyHandshake(ServerEndpointConfig config,
            HandshakeRequest request,
            HandshakeResponse response) {

        //put attributes from http session to websocket session
        HttpSession httpSession = (HttpSession) request.getHttpSession();
        config.getUserProperties().put("some_attribute",
               httpSession.getAttribute("some_attribute_in_http_session"));
    }
}

P. S. More a comment than an answer. I just wanted to add another way of handling session attributes in websocket to your question-answer. I have been searching the web for exactly the same issue and the way showed above seems to me the most systematic approach to handling the session data in websocket.

Konstantin K
  • 94
  • 1
  • 8
  • See also: http://stackoverflow.com/questions/31916727/request-or-session-scope-in-spring-websocket?noredirect=1&lq=1 – Konstantin K Jan 08 '17 at 17:54
  • Neither of these suggestions actually allows you to use a session-scoped bean as a field in a websocket handler, unfortunately. The second allows you to get them *programatically*, but for testability having the bean dependency injected is critical. I do have a solution to this, though, which I will write up when I've finished working on it. Unfortunately, it isn't simple... – Jules Jan 12 '17 at 02:33
  • @Jules I've written that it doesn't work for session scope. I think that's because websocket is aware of http above only on handshake, so this is naturally that you are not granted access to session-scoped beans as well. I used this solution for my project, where I have only one websocket endpoint, so I could pass user id in handshake only in one place of code and use beans from service layer that are not session-scoped. I have decided to post this solution here, even though it works only partially for the question posted. – Konstantin K Jan 12 '17 at 09:00