最近有一个项目,因为是多人一起做,加了不少的类库和配置,搞得最初建立的测试工程都启动不了,一直报一个错:
A ServletContext is required to configure default servlet handling
在网上查了,大多数人都说是肯定是spring 配置了不正确的东东,而原因有多个 ;
找了一个小时,也不知原因在哪里。
后来,发现了一篇文章说得较靠谱:
Caused by: java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling at org.springframework.util.Assert.notNull(Assert.java:112) at org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer.<init>(DefaultServletHandlerConfigurer.java:54) at org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.defaultServletHandlerMapping(WebMvcConfigurationSupport.java:329) at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$bb4ceb44.CGLIB$defaultServletHandlerMapping$22(<generated>) at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$bb4ceb44$$FastClassByCGLIB$$368bb5c1.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:326) at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$bb4ceb44.defaultServletHandlerMapping(<generated>) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166) ... 43 more
出错内容和我遇到的一模一样,之后答案是这样:
One of your @Configuration classes is obviously annotated with @EnableWebMvc. That's how DelegatingWebMvcConfiguration ends up in your stack trace, since it is imported by @EnableWebMvc. So although you think you don't need a WebApplicationContext (and hence a ServletContext), you in fact do need it simply because you are loading an application context with @EnableWebMvc. You have two options: •Compose the configuration classes for your integration test so that you are not including the web-related configuration (i.e., the @Configuration class(es) annotated with @EnableWebMvc). •Annotate your test class with @WebAppConfiguration as suggested in other comments above. Regards, Sam (author of the Spring TestContext Framework
记得好象代码里哪个地方好象真的加了@EnableWebMvc
在代码查找了一下,果然发现一个同事的websocket相关的代码加了这个标志;
package com.lansheng.web.websocket; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 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; @Configuration @EnableWebMvc @EnableWebSocket public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(systemWebSocketHandler(),"/webSocketServer").addInterceptors(new WebSocketHandshakeInterceptor()); registry.addHandler(systemWebSocketHandler(), "/sockjs/webSocketServer").addInterceptors(new WebSocketHandshakeInterceptor()) .withSockJS(); } @Bean public WebSocketHandler systemWebSocketHandler(){ return new SystemWebSocketHandler(); } }
将声明全部注释如下
package com.lansheng.web.websocket; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 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; //@Configuration //@EnableWebMvc //@EnableWebSocket public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(systemWebSocketHandler(),"/webSocketServer").addInterceptors(new WebSocketHandshakeInterceptor()); registry.addHandler(systemWebSocketHandler(), "/sockjs/webSocketServer").addInterceptors(new WebSocketHandshakeInterceptor()) .withSockJS(); } @Bean public WebSocketHandler systemWebSocketHandler(){ return new SystemWebSocketHandler(); } }
然后重新启动unit test;一切正常;
总结如下:
1.当调试这样提示的时候,肯定是spring配置出了问题;
2.spring配置出了问题,并不是单是找spring-context.xml或者spring-mvc.xml,还可能包括@Configuration声明的类;
3.在unit test的时候,因为跑的是appcontext,但是因为是web application项目,有的地方用了@EnableWebMvc,而导致运行环境认为你一定需要WebApplicationContext;提示你一定要将unit test 的class要加上转换声明,作为web app来运行;这时,你有两种选择,要么,将unit test 加上@WebAppConfiguration;要么将@EnableWebMvc的声明去掉;