Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean异常解析

Spring Boot升级到2.0.0,Maven构建成功,但是使用tomcat或jetty容器启动应用总是报错如下:

"C:\Program Files\Java\jdk1.8.0_161\bin\java" ......... com.fangxing.javalearning.annotationlearning.ComponentScanApp
hello world

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.0.RELEASE)

2018-04-03 22:25:07.232  INFO 4976 --- [           main] c.f.j.a.ComponentScanApp                 : Starting ComponentScanApp on DESKTOP-BHGM3HS with PID 4976 (started by hasee in D:\test\projects\java-learning)
2018-04-03 22:25:07.237  INFO 4976 --- [           main] c.f.j.a.ComponentScanApp                 : No active profile set, falling back to default profiles: default
2018-04-03 22:25:07.321  INFO 4976 --- [           main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@45f45fa1: startup date [Tue Apr 03 22:25:07 CST 2018]; root of context hierarchy
2018-04-03 22:25:07.664  WARN 4976 --- [           main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.
2018-04-03 22:25:08.238 ERROR 4976 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:155) ~[spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) ~[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.RELEASE.jar:2.0.0.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:388) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:327) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1246) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1234) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
    at com.fangxing.javalearning.annotationlearning.ComponentScanApp.main(ComponentScanApp.java:15) [classes/:na]
Caused by: org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getWebServerFactory(ServletWebServerApplicationContext.java:204) ~[spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:178) ~[spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:152) ~[spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
    ... 8 common frames omitted


Process finished with exit code 1

分析如下:

一、SpringBoot默认的容器为Tomcat,依赖包在spring-boot-starter-web下

<dependencies>  
        <dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-web</artifactId>  
        </dependency>  
  
        <dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-test</artifactId>  
            <scope>test</scope>  
        </dependency>  
  
</dependencies>  

二、SpringBoot把容器修改为Jetty

在pom.xml文件中,在引用的spring-boot-starter-web排除Tomcat的依赖包,然后再引入Jetty容器的依赖包,如下:

<dependencies>  
        <dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-web</artifactId>  
            <exclusions>  
                <exclusion>  
                    <groupId>org.springframework.boot</groupId>  
                    <artifactId>spring-boot-starter-tomcat</artifactId>  
                </exclusion>  
            </exclusions>  
        </dependency>  
  
        <!-- Jetty适合长连接应用,就是聊天类的长连接 -->  
        <!-- 使用Jetty,需要在spring-boot-starter-web排除spring-boot-starter-tomcat,因为SpringBoot默认使用tomcat -->  
        <dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-jetty</artifactId>  
        </dependency>  
        <dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-test</artifactId>  
            <scope>test</scope>  
        </dependency>  
</dependencies>  
 

三、为什么可以这样切换呢?

从SpringBoot源码中查看一下org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration类可知,使用哪个容器已经配置好,是根据依赖的Jar包自动切换,

加载Tomcat容器类代码和Jetty容器类代码如下:

/** 
     * Nested configuration if Tomcat is being used. 
     */  
    @Configuration  
    @ConditionalOnClass({ Servlet.class, Tomcat.class })  
    @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)  
    public static class EmbeddedTomcat {  
  
        @Bean  
        public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {  
            return new TomcatEmbeddedServletContainerFactory();  
        }  
  
    }  
  
    /** 
     * Nested configuration if Jetty is being used. 
     */  
    @Configuration  
    @ConditionalOnClass({ Servlet.class, Server.class, Loader.class,  
            WebAppContext.class })  
    @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)  
    public static class EmbeddedJetty {  
  
        @Bean  
        public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() {  
            return new JettyEmbeddedServletContainerFactory();  
        }  
  
    }  
  

类上@ConditionalOnClass注解,根据存在的依赖的容器Jar包判断使用哪个容器。

而Spring Boot启动出现错误,错误内容大概的意思是:未能加载嵌入的供web应用加载的空间,是因为缺少ServletWebServerFactory bean

在StackOverflow论坛中发现,这个问题与“Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean”如出一辙。

在stackflow上面看到了这个错误的解决办法,原文如下:

The scheduling guide isn't a web app so you probably have some mouldy stuff in your pom.xml from the REST guide? If you follow the instructions closely it should work. Another potential issue with the code you posted above is that your  @EnableAutoConfigurationclass is not used in the context, only as a main method (which may not be a problem for the scheduling guide but it probably is for a bunch of others).

这里意思是添加一个@EnableAutoConfiguration注解来解决问题。

其实不是技术论坛中大家常说的应用入口类缺少@SpringBootApplication标注,或者是Spring bean缺少@EnableAutoConfiguration标注等问题。
 

Spring Boot应用起不来,是因为默认使用的嵌入式Tomcat容器无法启动,即是容器依赖jar出问题了,最有可能原因是网上不好导致下载依赖包的过程中出现卡死或中断。

最直接的解决办法是删除Maven本地库中与容器包相关的依赖jar,再次构建下载新的jar。

启动Spring Boot应用,就可问题解决。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值