ugrade spring boot 2.0.0.RC2 exception No ServletContext set

前端 未结 2 1330
说谎
说谎 2020-12-10 14:11

After debugging, the problem is that mvc configuration class EnableWebMvcConfiguration load too early, servlet not loaded yet.

org.springframework.beans.fact         


        
相关标签:
2条回答
  • 2020-12-10 14:44

    "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!

    0 讨论(0)
  • 2020-12-10 15:00

    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

    0 讨论(0)
提交回复
热议问题