Add WebSocketAutoConfiguration
Opinionated defaults for WebSockets: * If spring-websocket is on the classpath and so is the Tomcat WSci initializer then it is added to the context * A DefaultSockJsService is added if none is present * User has only to define @Beans of type WebSocketHandler with name starting "/" * Each one is converted to a SockJsHttpRequestHandler and mapped to "/<beanName>/**"pull/50/head
parent
6e8cbbde3b
commit
767aa43e31
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.autoconfigure.websocket;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContainerInitializer;
|
||||||
|
|
||||||
|
import org.apache.catalina.Context;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
|
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.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||||
|
import org.springframework.web.socket.WebSocketHandler;
|
||||||
|
import org.springframework.web.socket.sockjs.SockJsHttpRequestHandler;
|
||||||
|
import org.springframework.web.socket.sockjs.SockJsService;
|
||||||
|
import org.springframework.web.socket.sockjs.support.AbstractSockJsService;
|
||||||
|
import org.springframework.web.socket.sockjs.transport.handler.DefaultSockJsService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto configuration for websockets (and sockjs in particular). Users should be able to
|
||||||
|
* just define beans of type {@link WebSocketHandler}. If <code>spring-websocket</code> is
|
||||||
|
* detected on the classpath then we add a {@link DefaultSockJsService} and an MVC handler
|
||||||
|
* mapping to <code>/<beanName>/**</code> for all of the
|
||||||
|
* <code>WebSocketHandler</code> beans that have a bean name beginning with "/".
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass({ WebSocketHandler.class })
|
||||||
|
@AutoConfigureBefore(EmbeddedServletContainerAutoConfiguration.class)
|
||||||
|
public class WebSocketAutoConfiguration {
|
||||||
|
|
||||||
|
private static class WebSocketEndpointPostProcessor implements BeanPostProcessor {
|
||||||
|
|
||||||
|
private Map<String, WebSocketHandler> prefixes = new HashMap<String, WebSocketHandler>();
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WebSocketHandler getHandler(String prefix) {
|
||||||
|
return this.prefixes.get(prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getPrefixes() {
|
||||||
|
return this.prefixes.keySet().toArray(new String[this.prefixes.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WebSocketEndpointPostProcessor webSocketEndpointPostProcessor() {
|
||||||
|
return new WebSocketEndpointPostProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(SockJsService.class)
|
||||||
|
public DefaultSockJsService sockJsService() {
|
||||||
|
DefaultSockJsService service = new DefaultSockJsService(sockJsTaskScheduler());
|
||||||
|
service.setSockJsClientLibraryUrl("https://cdn.sockjs.org/sockjs-0.3.4.min.js");
|
||||||
|
service.setWebSocketsEnabled(true);
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SimpleUrlHandlerMapping handlerMapping(SockJsService sockJsService,
|
||||||
|
Collection<WebSocketHandler> handlers) {
|
||||||
|
|
||||||
|
WebSocketEndpointPostProcessor processor = webSocketEndpointPostProcessor();
|
||||||
|
Map<String, Object> urlMap = new HashMap<String, Object>();
|
||||||
|
for (String prefix : webSocketEndpointPostProcessor().getPrefixes()) {
|
||||||
|
urlMap.put(prefix + "/**", new SockJsHttpRequestHandler(sockJsService,
|
||||||
|
processor.getHandler(prefix)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sockJsService instanceof AbstractSockJsService) {
|
||||||
|
((AbstractSockJsService) sockJsService).setValidSockJsPrefixes(processor
|
||||||
|
.getPrefixes());
|
||||||
|
}
|
||||||
|
SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
|
||||||
|
handlerMapping.setOrder(-1);
|
||||||
|
handlerMapping.setUrlMap(urlMap);
|
||||||
|
|
||||||
|
return handlerMapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(name = "sockJsTaskScheduler")
|
||||||
|
public ThreadPoolTaskScheduler sockJsTaskScheduler() {
|
||||||
|
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
|
||||||
|
taskScheduler.setThreadNamePrefix("SockJS-");
|
||||||
|
return taskScheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue