From 3bc37ddde0053aea656d918d55244713e729d155 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Tue, 4 Mar 2014 15:50:59 +0000 Subject: [PATCH] Strip out most of websocket autoconfig ... leaving only the embedded Tomcat enabling feature (registering the WsSci). Fixes part of gh-65 --- .../websocket/WebSocketAutoConfiguration.java | 115 +++--------------- .../config/SampleWebSocketsApplication.java | 17 ++- 2 files changed, 33 insertions(+), 99 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/websocket/WebSocketAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/websocket/WebSocketAutoConfiguration.java index 8f4101a8393..f1ba2ee74f8 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/websocket/WebSocketAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/websocket/WebSocketAutoConfiguration.java @@ -16,122 +16,45 @@ package org.springframework.boot.autoconfigure.websocket; -import java.util.HashMap; -import java.util.Map; - -import javax.servlet.ServletContainerInitializer; +import javax.servlet.Servlet; import org.apache.catalina.Context; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.ListableBeanFactory; -import org.springframework.beans.factory.config.BeanPostProcessor; +import org.apache.catalina.deploy.ApplicationListener; +import org.apache.catalina.startup.Tomcat; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration; import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.util.ClassUtils; import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.config.annotation.EnableWebSocket; -import org.springframework.web.socket.config.annotation.WebSocketConfigurer; -import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; -import org.springframework.web.socket.sockjs.transport.handler.DefaultSockJsService; /** - * Auto configuration for websocket server (and sockjs in particular). Users should be - * able to just define beans of type {@link WebSocketHandler}. If - * spring-websocket is detected on the classpath then we add a - * {@link DefaultSockJsService} and an MVC handler mapping to - * /<beanName>/** for all of the WebSocketHandler beans - * that have a bean name beginning with "/". + * Auto configuration for websocket server in embedded Tomcat. If + * spring-websocket is detected on the classpath then we add a listener that + * installs the Tomcat Websocket initializer. In a non-embedded container it should + * already be there. * * @author Dave Syer */ @Configuration -@ConditionalOnClass({ WebSocketHandler.class }) +@ConditionalOnClass(name = "org.apache.tomcat.websocket.server.WsSci", value = { + Servlet.class, Tomcat.class, WebSocketHandler.class }) @AutoConfigureBefore(EmbeddedServletContainerAutoConfiguration.class) -@ConditionalOnMissingBean(WebSocketConfigurer.class) -@EnableWebSocket public class WebSocketAutoConfiguration { - private static Log logger = LogFactory.getLog(WebSocketAutoConfiguration.class); + private static final ApplicationListener WS_APPLICATION_LISTENER = new ApplicationListener( + "org.apache.tomcat.websocket.server.WsContextListener", false); - // Nested class to avoid having to load WebSocketConfigurer before conditions are - // evaluated - @Configuration - protected static class WebSocketRegistrationConfiguration implements - BeanPostProcessor, BeanFactoryAware, WebSocketConfigurer { - - private final Map prefixes = new HashMap(); - - private ListableBeanFactory beanFactory; - - @Override - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = (ListableBeanFactory) beanFactory; - } - - @Override - public Object postProcessBeforeInitialization(Object bean, String beanName) - throws BeansException { - return bean; - } - - @Override - public Object postProcessAfterInitialization(Object bean, String beanName) - throws BeansException { - if (bean instanceof WebSocketHandler && beanName.startsWith("/")) { - this.prefixes.put(beanName, (WebSocketHandler) bean); + @Bean + public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() { + TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory() { + @Override + protected void postProcessContext(Context context) { + context.addApplicationListener(WS_APPLICATION_LISTENER); } - return bean; - } - - private WebSocketHandler getHandler(String prefix) { - return this.prefixes.get(prefix); - } - - private String[] getPrefixes() { - return this.prefixes.keySet().toArray(new String[this.prefixes.size()]); - } - - @Override - public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { - // Force initialization of WebSocketHandler beans - this.beanFactory.getBeansOfType(WebSocketHandler.class); - for (String prefix : getPrefixes()) { - logger.info("Adding SockJS handler: " + prefix); - registry.addHandler(getHandler(prefix), prefix).withSockJS(); - } - } - - } - - @Configuration - @ConditionalOnClass(name = "org.apache.tomcat.websocket.server.WsSci") - protected static class TomcatWebSocketConfiguration { - - @Bean - public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() { - TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory() { - @Override - protected void postProcessContext(Context context) { - context.addServletContainerInitializer( - (ServletContainerInitializer) BeanUtils - .instantiate(ClassUtils.resolveClassName( - "org.apache.tomcat.websocket.server.WsSci", - null)), null); - } - }; - return factory; - } - + }; + return factory; } } diff --git a/spring-boot-samples/spring-boot-sample-websocket/src/main/java/samples/websocket/config/SampleWebSocketsApplication.java b/spring-boot-samples/spring-boot-sample-websocket/src/main/java/samples/websocket/config/SampleWebSocketsApplication.java index 6233fd048c5..8d84d2fcd2d 100644 --- a/spring-boot-samples/spring-boot-sample-websocket/src/main/java/samples/websocket/config/SampleWebSocketsApplication.java +++ b/spring-boot-samples/spring-boot-sample-websocket/src/main/java/samples/websocket/config/SampleWebSocketsApplication.java @@ -23,6 +23,9 @@ import org.springframework.boot.context.web.SpringBootServletInitializer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.config.annotation.EnableWebSocket; +import org.springframework.web.socket.config.annotation.WebSocketConfigurer; +import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; import org.springframework.web.socket.handler.PerConnectionWebSocketHandler; import samples.websocket.client.GreetingService; @@ -34,7 +37,15 @@ import samples.websocket.snake.SnakeWebSocketHandler; @Configuration @EnableAutoConfiguration -public class SampleWebSocketsApplication extends SpringBootServletInitializer { +@EnableWebSocket +public class SampleWebSocketsApplication extends SpringBootServletInitializer implements + WebSocketConfigurer { + + @Override + public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { + registry.addHandler(echoWebSocketHandler(), "/echo").withSockJS(); + registry.addHandler(snakeWebSocketHandler(), "/snake").withSockJS(); + } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { @@ -55,12 +66,12 @@ public class SampleWebSocketsApplication extends SpringBootServletInitializer { return new SimpleGreetingService(); } - @Bean(name = "/echo") + @Bean public WebSocketHandler echoWebSocketHandler() { return new EchoWebSocketHandler(echoService()); } - @Bean(name = "/snake") + @Bean public WebSocketHandler snakeWebSocketHandler() { return new PerConnectionWebSocketHandler(SnakeWebSocketHandler.class); }