简体   繁体   English

Spring:如何将SimpMessagingTemplate bean暴露给root上下文?

[英]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). 我正在开发一个以Web为主框架的Java webapp(Spring核心,Spring mvc,Spring安全,Spring数据,Spring websocket特别使用)。

Declaring a message-broker in a Spring context like this provides a SimpMessagingTemplate bean to the context : 在这样的Spring上下文中声明一个message-broker ,为上下文提供了一个SimpMessagingTemplate bean:

<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). 我必须将此标记放在dispatcher-servlet.xml (而不是applicationContext.xml )中,否则客户端在尝试连接到websocket时会获得404(在初始页面加载时)。

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 ). 但是,由于此提供SimpMessagingTemplate bean的标记(向连接的客户端发送消息)在根上下文中不可用,因此当服务(由根上下文扫描)发送websocket消息时, SimpMessagingTemplate bean无法自动装配(经典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. 以前, <websocket:message-broker>标签位于applicationContext.xmldispatcher-servlet.xml正在导入applicationContext.xml ,一切正常 - 但是当我最近使用SessionRegistry时,我发现这是错误的SessionRegistry修改任意用户会话。

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). 实际上,由于DispatcherServlet明确地导入了已经隐含继承的根上下文,因此SessionRegistry bean被创建了两次,导致意外的行为(SO上有几个帖子描述了这个常见的错误,通常用户希望得到一个列表所有主体但由于SessionRegistry bean重复而获得空列表并找到相关信息。

So to fix this I removed the 所以为了解决这个问题,我删除了

<import resource="applicationContext.xml"/>

from the dispatcher-servlet.xml, but since then : 来自dispatcher-servlet.xml,但从那时起:

  • 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 或者我将<websocket:messagebroker>...</>标记放在dispatcher-servlet.xml中,在这种情况下,与websocket的连接成功但服务无法自动装配SimpMessagingTemplate
  • or I put the <websocket:messagebroker>...</> tag in applicationContext.xml , in which case clients cannot connect to websocket. 或者我在applicationContext.xml放置了<websocket:messagebroker>...</>标记,在这种情况下,客户端无法连接到websocket。
  • (or I go back to the previous version, where DispatcherServlet imports ApplicationContext , which breaks SessionRegistry - nope) (或者我回到之前的版本,其中DispatcherServlet导入ApplicationContext ,它打破了SessionRegistry - SessionRegistry

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 ? DispatcherServlet可以从根上下文访问bean,反之则不然,所以我应该如何处理?

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. 我不喜欢它,但鉴于SO上缺少答案(另请参阅: Dispatcher-servlet无法映射到websocket请求 ),以及当前和以前的同事,我不得不继续进行项目并实施一个脏的固定。

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 ). 脏的解决方法是AutowireSimpMessagingTemplate在控制器和预定类(全部由扫描dispatcher-servlet ,其中所述websocket tag被声明),以及传递SimpMessagingTemplate作为参数传递给服务方法(在声明root context )。

This solution is not transparent (the SimpMessagingTemplate should be autowired directly in services ideally) but it definitely fixes the problem. 这个解决方案不透明( SimpMessagingTemplate应该直接在服务中直接自动装配),但它肯定能解决问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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