升级 spring boot 2.0.0.RC2 异常 No ServletContext set
Posted
技术标签:
【中文标题】升级 spring boot 2.0.0.RC2 异常 No ServletContext set【英文标题】:ugrade spring boot 2.0.0.RC2 exception No ServletContext set 【发布时间】:2018-08-04 22:21:27 【问题描述】:经过调试,问题是mvc配置类EnableWebMvcConfiguration加载过早,servlet还没有加载。
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
【问题讨论】:
【参考方案1】:“经过调试,问题是mvc配置类EnableWebMvcConfiguration加载过早,servlet还没有加载。”
我在这上面花了几个小时。 我设法找到了发生这种情况的原因。 我的配置被拆分成几个文件,我在 Security Config(之前创建的)中创建了一个与 MVC 相关的 bean,从而强制在其时间之前使用 MVC 配置。
解决方案是将 @Bean 实例从安全配置移动到 MVC 配置。 我希望它可以帮助其他人!
【讨论】:
在我的例子中,它是MessageSource
bean,它已在WebMvcConfigurer
配置类中定义,同时被注入使用messageSource()
方法在同一类中创建其他一些bean打电话。当我删除方法调用注入并使用@Autowired
将messageSource
注入同一个类时,这个奇怪的错误变得更加明显:“创建名称为'messageSource'的bean时出错:当前正在创建请求的bean:是否存在无法解析的循环引用?”。所以我将MessageSource
bean 提取到另一个配置类中,它可以工作
也帮助了我!谢谢
说真的,为我节省了您花费的时间...感谢您的辛勤工作!【参考方案2】:
我有同样的“没有设置 ServletContext”的问题,我想通过做一个简单的演示来理解,这个演示帮助了我。所以我分享了我的简单演示,希望它也能对你有所帮助。 注意: (1) 我使用的示例与 OP 略有不同,但概念和问题是相同的。 (2) 我已经删除了一些与本次演示无关的日志。
Spring Boot Application 简单内容——只有 3 个类:
(1)一个主类BeanLoadingDemoApplication
用@SpringBootApplication注解,
(2) 一个class WebSecurityConfiguration extends WebSecurityConfigurerAdapter
,它覆盖了一个configure
方法
(3) 和几个测试 bean,一个在独立的 @Configuration
类中,另一个在 (2) 中的主 @SpringBootApplication
类中
启动应用程序后的日志如下。只需关注这部分在日志中的位置:
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();
...
在 WebSecurityConfiguration
类中为 Tomcat 配置第二个连接器。只需关注该部分“移动”的位置:
WebSecurityConfiguration() - 构造函数
你能看到构造函数是在启动应用程序后立即调用的,并且是在根WebApplicationContext
初始化之前构造的吗?至此,问题已经很清楚了。
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
原因是因为Spring Boot
在创建自己的WebApplicationContext
之前初始化嵌入的Tomcat
,因此它需要配置我正在添加到的连接器Tomcat
通过@Bean
在初始化 Tomcat 之前和在初始化 Root WebApplicationContext 之前!!但是因为我的 @Bean
在 WebSecurityConfiguration class
中,所以该类的构建时间比它应该的要早得多结果它不会有 ServletContext!!
解决方法是移动这个
@Bean
public ServletWebServerFactory servletContainer()
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
...
在一个@Configuration
独立类中,这样WebSecurityConfiguration
的构造函数就不会早于它应该被调用的时间,通过这样做,它将获得它需要的ServletContext
。
我希望这个“视觉”示例有所帮助。
干杯
【讨论】:
详细示例!谢谢以上是关于升级 spring boot 2.0.0.RC2 异常 No ServletContext set的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot 2.0干货系列:Spring Boot1.5X升级到2.0指南