简体   繁体   中英

Spring : how to expose SimpMessagingTemplate bean to root context ?

I'm developing a Java webapp with Spring as the main framework (Spring core, Spring mvc, Spring security, Spring data, Spring websocket are notably used).

Declaring a message-broker in a Spring context like this provides a SimpMessagingTemplate bean to the context :

<websocket:message-broker>
    <websocket:stomp-endpoint path="/stomp">
        <websocket:sockjs/>
    </websocket:stomp-endpoint>
    <websocket:simple-broker prefix="/topic,/queue"/>
</websocket:message-broker>

I have to put this tag in dispatcher-servlet.xml (not applicationContext.xml ), otherwise clients will get a 404 when trying to connect to the websocket (on initial page load).

However, since this tag which provides the SimpMessagingTemplate bean (to send messages to connected clients) is not available in the root context, when a service (scanned by the root context) sends a websocket message, the SimpMessagingTemplate bean cannot be autowired (classical NoSuchBeanDefinitionException ).

Previously, the <websocket:message-broker> tag was in applicationContext.xml and dispatcher-servlet.xml was importing applicationContext.xml and everything was working fine - however I found out to my surprise that this was wrong when I recently used a SessionRegistry to modify arbitrary user sessions.

Indeed, since the DispatcherServlet was explicitely importing the root context, which is already inherited implicitely, the SessionRegistry bean was created twice, leading to unexpected behaviours (there are several posts on SO that depict this common mistake, usually users want to get a list of all principals but get empty lists due to the SessionRegistry bean duplication and find out about this).

So to fix this I removed the

<import resource="applicationContext.xml"/>

from the dispatcher-servlet.xml, but since then :

  • either I put the <websocket:messagebroker>...</> tag in the dispatcher-servlet.xml, in which case connections to websocket are successful but services cannot autowire SimpMessagingTemplate
  • or I put the <websocket:messagebroker>...</> tag in applicationContext.xml , in which case clients cannot connect to websocket.
  • (or I go back to the previous version, where DispatcherServlet imports ApplicationContext , which breaks SessionRegistry - nope)

What is the solution to this probably rather common problem ? The DispatcherServlet can access beans from the root context but not vice-versa, so how should I work this out ?

I found a dirty solution. I don't like it, but given the lack of answers on SO (see also : Dispatcher-servlet cannot map to websocket requests ), as well as from current and former colleagues, I had to go forward with the project and implemented a dirty fix.

The dirty fix is to Autowire the SimpMessagingTemplate in Controller and Scheduled classes (all scanned by the dispatcher-servlet , where the websocket tag is declared), and to pass the SimpMessagingTemplate as a parameter to service methods (declared in the root context ).

This solution is not transparent (the SimpMessagingTemplate should be autowired directly in services ideally) but it definitely fixes the problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM