将 Spring Boot 战争部署到 Tomcat 服务器并收到“无法启动嵌入式 Tomcat org.springframework.context.ApplicationContextExcep
Posted
技术标签:
【中文标题】将 Spring Boot 战争部署到 Tomcat 服务器并收到“无法启动嵌入式 Tomcat org.springframework.context.ApplicationContextException”【英文标题】:Deployed Spring Boot war to Tomcat server and received "Unable to start embedded Tomcat org.springframework.context.ApplicationContextException" 【发布时间】:2021-10-26 08:10:35 【问题描述】:我正在关注Building an Application with Spring Boot 的指南。我的目标是在我的 Tomcat 服务器上运行该项目。
首先,我可以在 intellij 本地运行项目。
然后,我创建了一个名为 sample.war
的战争,并按照 12.17.1. Create a Deployable War File 将其部署到我的 Tomcat 服务器。然后我将war
放入目录webapps/sample.war
。但是,它无法运行。关键错误(完整日志见下文):
2021-08-26 16:40:37,453 [localhost-startStop-15] ERROR o.s.b.SpringApplication - Application run failed
org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'formContentFilter' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.web.servlet.filter.OrderedFormContentFilter]: Factory method 'formContentFilter' threw exception; nested exception is java.lang.VerifyError: Bad return type
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'formContentFilter' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.web.servlet.filter.OrderedFormContentFilter]: Factory method 'formContentFilter' threw exception; nested exception is java.lang.VerifyError: Bad return type
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>serving-web-content-complete</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>serving-web-content-complete</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
servingwebcontent\GreetingController.java
:
package com.example.servingwebcontent;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class GreetingController
@GetMapping("/greeting")
public String greeting(@RequestParam(name = "name", required = false, defaultValue = "World") String name, Model model)
model.addAttribute("name", name);
return "greeting";
ServingWebContentApplication.java
package com.example.servingwebcontent;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
public class ServingWebContentApplication extends SpringBootServletInitializer
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
return application.sources(ServingWebContentApplication.class);
public static void main(String[] args)
SpringApplication.run(ServingWebContentApplication.class, args);
服务器信息:
Server version: Apache Tomcat/8.5.20
Server number: 8.5.20.0
OS Name: Linux
OS Version: 5.4.0-77-generic
下面请看catalina.out
的错误日志:
26-Aug-2021 16:40:35.813 INFO [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.startup.HostConfig.undeploy Undeploying context [/sample]
26-Aug-2021 16:40:35.824 INFO [localhost-startStop-15] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/opt/apache-tomcat-8.5.20/webapps/sample.war]
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/opt/apache-tomcat-8.5.20/lib/news-client-0.7.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/opt/apache-tomcat-8.5.20/webapps/sample/WEB-INF/lib/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.2)
2021-08-26 16:40:37,453 [localhost-startStop-15] ERROR o.s.b.SpringApplication - Application run failed
org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'formContentFilter' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.web.servlet.filter.OrderedFormContentFilter]: Factory method 'formContentFilter' threw exception; nested exception is java.lang.VerifyError: Bad return type
Exception Details:
Location:
org/springframework/http/converter/json/Jackson2ObjectMapperBuilder$SmileFactoryInitializer.create()Lcom/fasterxml/jackson/core/JsonFactory; @7: areturn
Reason:
Type 'com/fasterxml/jackson/dataformat/smile/SmileFactory' (current frame, stack[0]) is not assignable to 'com/fasterxml/jackson/core/JsonFactory' (from method signature)
Current Frame:
bci: @7
flags:
locals: 'org/springframework/http/converter/json/Jackson2ObjectMapperBuilder$SmileFactoryInitializer'
stack: 'com/fasterxml/jackson/dataformat/smile/SmileFactory'
Bytecode:
0x0000000: bb00 0359 b700 04b0
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:163)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:577)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:338)
at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:175)
at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:155)
at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:97)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:174)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5196)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:752)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:728)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:734)
at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:988)
at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1860)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'formContentFilter' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.web.servlet.filter.OrderedFormContentFilter]: Factory method 'formContentFilter' threw exception; nested exception is java.lang.VerifyError: Bad return type
[nipped with more of the same errors]
26-Aug-2021 16:40:37.531 INFO [localhost-startStop-15] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/opt/apache-tomcat-8.5.20/webapps/sample.war] has finished in [1,708] ms
这是我迄今为止尝试过的:
我有ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean 中提到的确切问题。我已经听从了三个案例的建议,但无济于事:
案例 1:@SpringBootApplication
注释没有丢失
案例 2:不适用,因为我的项目是 web 项目
案例3:我不使用spring-boot-starter-webflux
我有 Unable to start embedded Tomcat org.springframework.context.ApplicationContextException 中提到的确切问题,但我们没有相同的原因。
我尝试使用旧版本的com.fasterxml.jackson.core
添加,如java.lang.NoClassDefFoundError: com/fasterxml/jackson/core/JsonFactory 中提到的2.8.10,但无济于事。
非常非常感谢任何帮助。
【问题讨论】:
Spirng Boot 2.5 需要 Tomcat 9。 @M.Deinum:你有参考吗?据我了解 Spring 5.x 的 baseline requirements 是 Servlet 3.1。如果可用,则使用 Servlet 4.0。 “SLF4J:在 [jar:file:/opt/apache-tomcat-8.5.20/lib/news-client-0.7.2.jar”中找到绑定:你有一个修改过的 Tomcat 安装。请尝试全新安装或提供您在/opt/apache-tomcat-8.5.20/lib
中添加的库列表。
我认为 Boot(不是 Spring 本身)的最小值是 tomcat 9。但是查看验证错误,您可能在不同的类加载器的路径中的某处有一个重复的 servlet-api,导致各种的问题。
jackson-dataformat-smile
的副本必须在服务器的类路径中,并且可以被ServiceLoader
检测到。如果该库确实必须存在(可能不是),那么应该有一种方法可以禁用自动检测。
【参考方案1】:
如 cmets 中所述,问题来自您的系统管理员在 Tomcat 的类路径中放置的 jackson-dataformat-smile
库。
如果您真的无法摆脱它,您可以使用以下三种解决方案之一:
将该库添加到您的项目依赖项中(它将覆盖 Tomcat 类路径中的那个),
禁用MappingJackson2SmileHttpMessageConverter
:与前面所说的不同,SmileFactory
不被 ServiceLoader
检测到,但如果 Spring 检测到工厂开启,它会显式调用它的类路径(参见WebMvcConfigurationSupport #addDefaultMessageConverters
)。这是通过将库添加到类路径中“神奇地”出现的功能的价格。
幸运的是,您可以覆盖默认消息转换器:只需添加 WebMvcConfigurer
并覆盖其 configureMessageConverters
。你甚至可以在你的@SpringBootApplication
课堂上做到这一点:
@SpringBootApplication
public class YourSpringApplication implements WebMvcConfigurer
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters)
// add configuration here
...
您可以复制上述addDefaultMessageConverters
的部分内容。
通过添加到您的上下文文件来更改类加载器的搜索顺序(参见Documentation 的方法并更改加载器的delegate
属性:
<Context>
<Loader delegate="true" />
...
</Context>
【讨论】:
我已经尝试过您提到的选项 1。但是,问题仍然存在。原来是jar:file:/opt/apache-tomcat-8.5.20/lib/news-client-0.7.2.jar
导致了错误。一旦我的系统管理员删除它,问题就消失了。再次感谢你。我真的很感激。以上是关于将 Spring Boot 战争部署到 Tomcat 服务器并收到“无法启动嵌入式 Tomcat org.springframework.context.ApplicationContextExcep的主要内容,如果未能解决你的问题,请参考以下文章
我如何使用部署在战争 Spring Boot 应用程序中的 mysql jdbc 驱动程序