Servlet dispatcher cannot match websocket requests

I am developing a Java webapp with Spring as the main framework (Spring core, Spring mvc, Spring security, Spring data, Spring websocket).

Declaring a message broker in a Spring context like this provides a SimpMessagingTemplate bean for 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 need to put this tag in my root context (applicationContext.xml), otherwise the services declared in this root context cannot send notifications to users via websocket (because they need SimpMessagingTemplate).

The fact is that if I put this tag in the root context, clients get 404 when they subscribe to websocket. And if I put the tag in the servlet dispatcher, then the services in the root context cannot send notifications, since they will need a SimpMessagingTemplate (but it is only available in the context of the servlet dispatcher of the child dispatcher).

Is there a way to "link" a servlet dispatcher to a broker? Declaring a bean twice is not the right decision.

This problem is the same as Spring: how to put the SimpMessagingTemplate bean in the root context? but looking at a different angle (websocket declaration in the root context and not in the dispatcher servlet)

+4
2

. , , SO, , .

Autowire SimpMessagingTemplate Controller Scheduled ( dispatcher-servlet, websocket tag), SimpMessagingTemplate ( root context).

(SimpMessagingTemplate ), .

+1

bean, , . , SimpMessageTemplate

bean, :

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

PostInjectSimpMessageTemplateBean:

bean (.. XML , websocket)

( "YOUR.PACKAGE.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();
    }
}
}
0

All Articles