2016-03-15 46 views
4

我正在开发和春天有个Java的Web应用中的主要框架(弹簧芯,Spring MVC的,春天的安全性,数据春,春天的WebSocket也有明显的使用)。调度-的servlet不能映射到的WebSocket请求

声明在Spring上下文的消息,经纪人这样提供SimpMessagingTemplate豆上下文:

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

我必须把这个标签在我的根上下文(applicationContext.xml中),另有声明的服务根上下文无法通过websocket发送通知给用户(因为他们需要SimpMessagingTemplate)。

的事情是,如果我把这个标签在根上下文,客户收到了404当他们订阅的WebSocket。如果我把标签在调度员的servlet,然后在根上下文服务无法发送通知,因为他们需要的SimpMessagingTemplate(但它仅适用于子调度员servlet上下文)。

有没有办法“绑定”的调度员的servlet的经纪人?两次声明这个bean不是一个正确的解决方案。

此问题是相同的,但Spring : how to expose SimpMessagingTemplate bean to root context ?从另一个角度看(在根上下文,而不是在调度员的servlet声明的WebSocket)

回答

1

我发现了一个脏溶液。我不喜欢它,但由于缺乏SO以及现任和前任同事的答案,我不得不继续进行该项目并实施了一个肮脏的修复程序。

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

此解决方案不透明(SimpMessagingTemplate应直接在服务中直接自动布线),但它绝对可以解决问题。

0

我已经写了豆inited servlet的应用程序上下文后做注射。

@Autowired(required=false) //required=false so that it won't throw Exception when startup 
private SimpMessagingTemplate messagingTemplate; 

PostInjectSimpMessageTemplateBean:它会通过父应用程序上下文以注入SimpMessageTemplate

无论豆需要模板搜索

将这个bean的servlet应用程序上下文(即websocket所在的同一个xml文件)

将“YOUR.P ACKAGE.NAME”

public class PostInjectSimpMessageTemplateBean implements ApplicationListener<ContextRefreshedEvent> { 

@Override 
public void onApplicationEvent(ContextRefreshedEvent event) { 
    ApplicationContext servletContext = event.getApplicationContext(); 
    ApplicationContext context = servletContext.getParent(); 

    SimpMessagingTemplate template = servletContext.getBean(SimpMessagingTemplate.class); 

    while(context != null){ 
     for(String beanName : context.getBeanDefinitionNames()){ 
      Object bean = context.getBean(beanName); 
      Class<?> clazz = bean.getClass(); 
      if(!clazz.getName().startsWith("YOUR.PACKAGE.NAME")) continue; 

      List<FieldWithAnnotation<Autowired>> fields = ReflectionUtils.findFieldsWithAnnotation(clazz, Autowired.class); 
      for (FieldWithAnnotation<Autowired> fieldWithAnno : fields) { 
       Field field = fieldWithAnno.getField(); 
       if(field.getType() == SimpMessagingTemplate.class){ 
        field.setAccessible(true); 
        try { 
         field.set(bean, template); 
        } catch (Exception e) {} 
       } 
      } 

      List<Method> methods = ReflectionUtils.findMethodsWithAnnotation(clazz, Autowired.class); 
      for (Method method : methods) { 
       Class<?>[] paramtypes = method.getParameterTypes(); 
       if(paramtypes.length == 1){ 
        if(paramtypes[0] == SimpMessagingTemplate.class){ 
         method.setAccessible(true); 
         try { 
          method.invoke(bean, template); 
         } catch (Exception e) {} 
        } 
       } 
      } 
     } 

     context = context.getParent(); 
    } 
} 
}