问题
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 autowireSimpMessagingTemplate
- or I put the
<websocket:messagebroker>...</>
tag inapplicationContext.xml
, in which case clients cannot connect to websocket. - (or I go back to the previous version, where
DispatcherServlet
importsApplicationContext
, which breaksSessionRegistry
- 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 ?
回答1:
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.
来源:https://stackoverflow.com/questions/34774158/spring-how-to-expose-simpmessagingtemplate-bean-to-root-context