variable una sesiones sesion servlet que manejo manejar como clases java spring spring-mvc websocket

una - session java



Contexto de aplicación de raíz de Spring y confusión de contexto de servlet (2)

Sé que necesito registrar las clases anotadas en @Controller en el contexto de mi servlet para hacer accesible mi aplicación web. Usualmente, lo hago de la siguiente manera:

@Configuration @EnableWebMvc @ComponentScan({"foo.bar.controller"}) public class WebConfig extends WebMvcConfigurerAdapter { //other stuff like ViewResolvers, MessageResolvers, MessageConverters, etc. }

Todas las demás clases de configuración que agregué a mi contexto de aplicación raíz. Aquí es cómo mi inicializador dispetcher generalmente se ve como:

public class DispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class<?>[] { RootConfig.class, ServiceConfig.class }; } @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[] { WebConfig.class }; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } }

Pero las cosas se están poniendo más interesantes cuando comencé a usar WebSockets. Para que Websockets funcione, debe colocar WebSoketConfig.class en el contexto de servlet. Aquí está mi ejemplo de WebSocketConfig:

@Configuration @EnableScheduling @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/chat").withSockJS(); } @Override public void configureClientInboundChannel(ChannelRegistration channelRegistration) { channelRegistration.taskExecutor().corePoolSize(4).maxPoolSize(8); } @Override public void configureClientOutboundChannel(ChannelRegistration channelRegistration) { channelRegistration.taskExecutor().corePoolSize(4).maxPoolSize(8); } @Override public void configureMessageBroker(MessageBrokerRegistry registry) { registry.enableSimpleBroker("/queue", "/topic"); registry.setApplicationDestinationPrefixes("/app"); } }

Además, he creado un servicio para enviar un mensaje al tema:

@Service public class TimeServiceWsImpl implements TimeServiceWs { @Autowired private SimpMessagingTemplate messagingTemplate; @Override public void sentCurrentTime() { long currentTime = System.currentTimeMillis(); String destination = "/topic/chatty"; logger.info("sending current time to websocket /topic/time : " + currentTime); this.messagingTemplate.convertAndSend(destination, currentTime); } }

Necesito usar este servicio en otros servicios (autorizarlo). Y ahora estoy en punto muerto.

  1. Si estoy intentando crear el bean TimeServiceWs dentro del contexto de la aplicación raíz, como se esperaba, no ve el bean SimpMessagingTemplate y lanza la NoSuchBeanDefinitionException
  2. Si estoy tratando de crear el bean TimeServiceWs dentro del contexto del servlet, entonces no puedo conectarlo automáticamente a ningún otro servicio, porque el contexto raíz no puede ver los beans del contexto del servlet (que yo sepa)
  3. Si muevo todas mis configuraciones al contexto de servlet, todos los beans se crean con éxito, pero obtengo la siguiente excepción: java.lang.IllegalStateException: No WebApplicationContext found y no puedo acceder a mi aplicación web

¿Que se supone que haga? ¿Qué debería estar dentro del contexto raíz? ¿Qué debería estar dentro del contexto servlet? ¿Y podría aclarar la diferencia entre estos contextos una vez más, por favor?

Si necesita información adicional, hágamelo saber.


La configuración relacionada con WebSocket pertenece a la configuración de DispatcherServlet de una manera u otra. Después de que todo el protocolo de enlace HTTP sea procesado por el DispatcherServlet a través de sus asignaciones de controlador.

Debería poder ir con un solo contexto Spring en un escenario de implementación donde solo haya un DispatcherServlet en la aplicación web. Consolidar la configuración en el contexto raíz tiene más sentido si se usa Spring Security, por ejemplo, aunque hubo un error con AbstractAnnotationConfigDispatcherServletInitializer (consulte SPR-11357 ). La consolidación en el contexto de DispatcherServlet también debería ser posible, pero usted escribió que obtuvo excepciones. ¿Puede proporcionar los detalles de la excepción?

También es una opción tener ambos contextos raíz y DispatcherServlet. En ese caso, la configuración de WebSocket estará en el contexto de DispatcherServlet y no es posible inyectar SimpMessagingTemplate en beans en el contexto raíz. Eso realmente tiene sentido, ya que hay un SimpMessagingTemplate para ir con cada DispatcherServlet (o algún otro servlet). Lo que se necesita es un componente de capa web, quizás un envoltorio delgado alrededor de los beans de la capa de servicio (como TimeService, el ejemplo anterior) que también se puede inyectar con la plantilla SimpMessaging. Este componente de capa web sirve esencialmente como un puente.


La mayoría de las aplicaciones Spring MVC tienen un contexto raíz que contiene todos los beans de capa de servicio / capa DAO, y un contexto de servlet por cada servlet de despachador de la aplicación, que contiene (al menos) los controladores de cada servlet.

La idea es que una aplicación puede tener varios distribuidores de servlets, por ejemplo, uno para URL /shopping/* y otro para URL /reporting/* , cada uno con su propio conjunto de controladores.

Los controladores de un despachador de servlets están aislados unos de otros, lo que significa que, aunque también son frijoles de primavera, no se pueden inyectar entre sí.

La capa de servicio y los beans DAO en el contexto raíz son visibles en todos los contextos de servlet, por lo que los beans de capa de servicio se pueden inyectar en cualquier controlador, pero no al revés.

Se dice que el contexto raíz es el padre del contexto / contextos del servlet del controlador.

Todo está destinado a ser un mecanismo de aislamiento de grupos de beans entre sí para garantizar que no sean posibles dependencias no intencionadas.

Dado esto y pasando por las preguntas:

  • Si estoy tratando de crear el bean TimeServiceWs dentro del contexto de la aplicación raíz, como se esperaba, no ve el bean SimpMessagingTemplate y arroja NoSuchBeanDefinitionException: Mueve el SimpleMessagingTemplate al contexto raíz, es un bean como un DAO que puede ser útil en cualquier lugar de la aplicación. debería estar en el contexto raíz compartido.

  • Si estoy tratando de crear el bean TimeServiceWs dentro del contexto del servlet, entonces no puedo conectarlo automáticamente a ningún otro servicio : si está destinado a ser conectado automáticamente a otros servicios, déjelo en el contexto raíz entonces.

    - Si muevo todas mis configuraciones al contexto de servlet, todos los beans se crean con éxito, pero obtengo java.lang.IllegalStateException: No se encontró WebApplicationContext: haga lo contrario, mueva básicamente todos los beans al contexto raíz, y deje solo el contexto del servlet Los beans que son específicos de esa parte de la aplicación, muchas veces solo los controladores.