After debugging, the problem is that mvc configuration class EnableWebMvcConfiguration load too early, servlet not loaded yet.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'resourceHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.HandlerMapping]: Factory method 'resourceHandlerMapping' threw exception; nested exception is java.lang.IllegalStateException: No ServletContext set
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:587) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1250) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1099) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:502) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:312) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$125/98506158.getObject(Unknown Source) ~[na:na]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:310) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:760) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:868) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.0.0.RC2.jar:2.0.0.RC2]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) [spring-boot-2.0.0.RC2.jar:2.0.0.RC2]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:388) [spring-boot-2.0.0.RC2.jar:2.0.0.RC2]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:327) [spring-boot-2.0.0.RC2.jar:2.0.0.RC2]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1246) [spring-boot-2.0.0.RC2.jar:2.0.0.RC2]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1234) [spring-boot-2.0.0.RC2.jar:2.0.0.RC2]
at com.manway.BccApplication.main(BccApplication.java:16) [main/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_40]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_40]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_40]
at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_40]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-2.0.0.RC2.jar:2.0.0.RC2]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.HandlerMapping]: Factory method 'resourceHandlerMapping' threw exception; nested exception is java.lang.IllegalStateException: No ServletContext set
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:579) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
... 24 common frames omitted
Caused by: java.lang.IllegalStateException: No ServletContext set
at org.springframework.util.Assert.state(Assert.java:73) ~[spring-core-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.resourceHandlerMapping(WebMvcConfigurationSupport.java:485) ~[spring-webmvc-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration$$EnhancerBySpringCGLIB$$5de64506.CGLIB$resourceHandlerMapping$40(<generated>) ~[spring-boot-autoconfigure-2.0.0.RC2.jar:2.0.0.RC2]
at org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration$$EnhancerBySpringCGLIB$$5de64506$$FastClassBySpringCGLIB$$edc706a5.invoke(<generated>) ~[spring-boot-autoconfigure-2.0.0.RC2.jar:2.0.0.RC2]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) ~[spring-core-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:361) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration$$EnhancerBySpringCGLIB$$5de64506.resourceHandlerMapping(<generated>) ~[spring-boot-autoconfigure-2.0.0.RC2.jar:2.0.0.RC2]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_40]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_40]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_40]
at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_40]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
... 25 common frames omitted
"After debugging, the problem is that mvc configuration class EnableWebMvcConfiguration load too early, servlet not loaded yet."
I spent a few hours on this. I managed to find a reason why this was happening. My config was split into several files and I was creating a MVC related bean in the Security Config (which was created earlier) forcing to use the MVC config before its time.
The solution was to move the @Bean instance from the security config to the MVC config. I hope it helps other people!
I have the same "No ServletContext set" issue, and i wanted to understand by doing a simple demo.
Notes:
(1) The example i am using is slightly different from the OP but the concept and issue is the same.
(2) I have removed some logs that are not relevant.
DEMO: SIMPLE Spring Boot Application:
(1) a main class BeanLoadingDemoApplication
annotated with @SpringBootApplication
,
(2) a class WebSecurityConfiguration extends WebSecurityConfigurerAdapter
, which overrides configure
method
(3) and a couple of test beans, 1 in a stand-alone @Configuration
class, and the other one in the main @SpringBootApplication
class
P.S1 WebApplicationContext
object is the Spring Container, that is based on your business bean definitions, stored in the ServletContext of the web application.
P.S2 So after it's initialized, you will see your beans being initialized(testBean and testBean2, in my example).
The logs after starting the application is as follows. Just focus on where this part is in the logs:
INFO o.s.web.context.ContextLoader - Root WebApplicationContext: initialization completed in 700 ms INFO c.example.demo.WebSecurityConfiguration - WebSecurityConfiguration() - Constructor
INFO c.e.demo.BeanLoadingDemoApplication - Starting BeanLoadingDemoApplication
INFO o.s.b.w.embedded.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http)
INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
INFO o.s.web.context.ContextLoader - Root WebApplicationContext: initialization completed in 700 ms
INFO c.example.demo.WebSecurityConfiguration - WebSecurityConfiguration() - Constructor
INFO com.example.demo.TestBeanConfiguration - #############################
INFO com.example.demo.TestBeanConfiguration - @Configuration - @Bean - testBean()
INFO com.example.demo.TestBeanConfiguration - #############################
INFO c.e.demo.BeanLoadingDemoApplication - #############################
INFO c.e.demo.BeanLoadingDemoApplication - @SringBootApp - @Bean - testBean2
INFO c.e.demo.BeanLoadingDemoApplication - #############################
INFO c.example.demo.WebSecurityConfiguration - =======================================
INFO c.example.demo.WebSecurityConfiguration - @Configuration - WebSecurityConfiguration - @Override configure
INFO c.example.demo.WebSecurityConfiguration - =======================================
INFO c.e.demo.BeanLoadingDemoApplication - Started BeanLoadingDemoApplication in 1.371 seconds (JVM running for 2.326)
@Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
...
}
in class WebSecurityConfiguration
to configure a 2nd connector for Tomcat. Just focus where this part has "moved":
WebSecurityConfiguration() - Constructor
Can you see that the constructor is called right after starting the application and has been constructed before the root WebApplicationContext
is initialized? By now, the issue is clear.
INFO c.e.demo.BeanLoadingDemoApplication - Starting BeanLoadingDemoApplication
INFO c.example.demo.WebSecurityConfiguration - WebSecurityConfiguration() - Constructor
INFO o.s.b.w.embedded.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) 8080 (http)
INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
INFO o.s.web.context.ContextLoader - Root WebApplicationContext: initialization completed in 785 ms
INFO com.example.demo.TestBeanConfiguration - #############################
INFO com.example.demo.TestBeanConfiguration - @Configuration - @Bean - testBean()
INFO com.example.demo.TestBeanConfiguration - #############################
INFO c.e.demo.BeanLoadingDemoApplication - #############################
INFO c.e.demo.BeanLoadingDemoApplication - @SringBootApp - @Bean - testBean2
INFO c.e.demo.BeanLoadingDemoApplication - #############################
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'resourceHandlerMapping' defined in class path resource
Caused by: java.lang.IllegalStateException: No ServletContext set
The reason is since Spring Boot
is initializing the embedded Tomcat
before creating its own WebApplicationContext
, it therefore needs to configure the connector i am adding to Tomcat
via the @Bean
before initializing Tomcat and before Root WebApplicationContext is initialized!! But because my @Bean
is in WebSecurityConfiguration class
, that class is getting constructed much earlier than it should have been and it will not have a ServletContext as a result!!
The solution is to move this
@Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
...
}
in a @Configuration
stand-alone class, so that the constructor of WebSecurityConfiguration
is not called earlier than it should have been, and by doing so, it will get the ServletContext
it needs.
I hope this "visual" example helps.
Cheers
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With