Spring-boot Unable to start EmbeddedWebApplicationContext 分析与解决方法
2017-08-06 11:40
761 查看
异常触发背景
项目中依赖了第三方的dubbo调用依赖。<dependency> <groupId>xxx.xxx.com</groupId> <artifactId>dubbo-test-client</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
随后启动spring-boot application后产生异常
org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean. Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
异常产生原因
在启动时Spring-boot会检查当前环境,org.springframework.boot.SpringApplication内部维护 webEnvironment成员,记录当前是否是web环境。private boolean webEnvironment;
在启动时会沿如下的调用路径通过deduceWebEnvironment方法判断当前环境,并给webEnvironment变量赋值。
this.webEnvironment = deduceWebEnvironment();
at org.springframework.boot.SpringApplication.deduceWebEnvironment(SpringApplication.java:256) at org.springframework.boot.SpringApplication.initialize(SpringApplication.java:248) at org.springframework.boot.SpringApplication.<init>(SpringApplication.java:225) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) at springboot.commandline.StartupRunner.main(StartupRunner.java:36)
deduceWebEnvironment,通过尝试加载WEB_ENVIRONMENT_CLASSES数组中的下面两个类,如果全部加载成功那么推断当前属于web环境。
javax.servlet.Servlet(servelet-api jar)
org.springframework.web.context.ConfigurableWebApplicationContext (spring-web jar)
private boolean deduceWebEnvironment() { for (String className : WEB_ENVIRONMENT_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return false; } } return true; }
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext" };
由于在maven中添加的依赖同时引入WEB_ENVIRONMENT_CLASSES中的类,导致spring-boot判断当前为web环境。
当判断为web环境,会在springboot.run方法中通过createApplicationContext()方法创建EmbeddedWebApplicationContext,最终会沿如下的调用链调用createEmbeddedServletContainer()方法去创建servlet容器。
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(EmbeddedWebApplicationContext.java:159) at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:134) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537) - locked <0xbc0> (a java.lang.Object) at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) at springboot.commandline.StartupRunner.main(StartupRunner.java:36)
在createEmbeddedServletContainer中会通过getEmbeddedServletContainerFactory()方法来获取容器工厂对象。
private void createEmbeddedServletContainer() { EmbeddedServletContainer localContainer = this.embeddedServletContainer; ServletContext localServletContext = getServletContext(); if (localContainer == null && localServletContext == null) { EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory(); this.embeddedServletContainer = containerFactory .getEmbeddedServletContainer(getSelfInitializer()); } else if (localServletContext != null) { try { getSelfInitializer().onStartup(localServletContext); } catch (ServletException ex) { throw new ApplicationContextException("Cannot initialize servlet context", ex); } } initPropertySources(); }
getEmbeddedServletContainerFactory 方法被调用时会尝试获取工厂bean名称,如果获取不到,则会抛出Unable to start EmbeddedWebApplicationContext due to missing的异常。
protected EmbeddedServletContainerFactory getEmbeddedServletContainerFactory() { // Use bean names so that we don't consider the hierarchy String[] beanNames = getBeanFactory() .getBeanNamesForType(EmbeddedServletContainerFactory.class); if (beanNames.length == 0) { throw new ApplicationContextException( "Unable to start EmbeddedWebApplicationContext due to missing " + "EmbeddedServletContainerFactory bean."); } if (beanNames.length > 1) { throw new ApplicationContextException( "Unable to start EmbeddedWebApplicationContext due to multiple " + "EmbeddedServletContainerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames)); } return getBeanFactory().getBean(beanNames[0], EmbeddedServletContainerFactory.class); }
总结:通过对异常产生的原因分析,可以知道是因为引入了spring-web-xx.jar(xx为版本号),导致判断当前环境为web,最终尝试创建相关的Servlet容器工厂失败而导致。
最后分析maven依赖关系发现依赖的包dubbo-test-client存在对spring-web的间接依赖。
解决方法
1.在dubbo-test-client中排除对spring-web jar的依赖。<dependency> <groupId>xxx.xxx.xx</groupId> <artifactId>dubbo-test-client</artifactId> <version>1.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </exclusion> </exclusions> </dependency>
2.引入spring-boot-starter-web,引入创建web容器所需要的相关依赖。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
参考
spring-boot 1.5.6 源码相关文章推荐
- Spring Boot: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFa
- 从eclipse中导入到IDEA中的SpringBoot项目,启动时报错 Unable to start EmbeddedWebApplicationContext due to missing Em
- IDEA启动spring boot 出现Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletCont
- IDEA启动Spring Boot项目提示Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServlet...
- SpringbootUnable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFact
- IDEA执行spring boot 出现Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletCont
- 【Spring Cloud】Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletCon
- 【Spring Cloud】Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletCon
- 【Spring Cloud】Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletCon
- 【Spring Cloud】Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletCon
- 关于spring boot org.springframework.context.ApplicationContextException:Unable to start Embedded解决方案
- 【Spring Cloud】Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletCon
- 【Spring Cloud】Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletCon
- 【Spring Cloud】Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletCon
- 【Spring Cloud】Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletCon
- 【Spring Cloud】Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletCon
- 【Spring Cloud】Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletCon
- Spring Cloud | Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainer
- 【Spring Cloud】Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletCon
- 【Spring Cloud】Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletCon