After debugging, the problem is that mvc configuration class EnableWebMvcConfiguration load too early, servlet not loaded yet.
org.springframework.beans.fact
I have the same "No ServletContext set" issue, and i wanted to understand by doing a simple demo, and the demo has helped me. So i am sharing my simple demo in the hope that it helps you too.
Note:
(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 for this demo.
Spring Boot Application simple content - just 3 class:
(1) a main class BeanLoadingDemoApplication annotated with @SpringBootApplication,
(2) a class WebSecurityConfiguration extends WebSecurityConfigurerAdapter, which overrides one 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 in (2)
The logs after starting the application is as follows below. Just focus on where this part is in the log:
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)
So far ok? Simple, right? Now i add a
@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