首页 > 解决方案 > 将 Spring Boot 战争部署到 Tomcat 服务器并收到“无法启动嵌入式 Tomcat org.springframework.context.ApplicationContextException”

问题描述

我正在遵循使用 Spring Boot 构建应用程序的指南。我的目标是在我的 Tomcat 服务器上运行该项目。

首先,我可以在 intellij 本地运行项目。

然后,我创建了一个名为 war并按照12.17.1sample.war将其部署到我的 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

这是我到目前为止所尝试的:

  1. 我有ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean中提到的确切问题。我遵循了三个案例的建议,但无济于事:

    案例1:@SpringBootApplication注释不丢失

    案例 2:不适用,因为我的项目是 web 项目

    案例3:我不使用spring-boot-starter-webflux

  2. 我有无法启动嵌入式 Tomcat org.springframework.context.ApplicationContextException中提到的确切问题,但我们没有相同的原因。

  3. 我尝试使用java.lang.NoClassDefFoundError: com/fasterxml/jackson/core/JsonFactorycom.fasterxml.jackson.core中提到的 2.8.10 之类的旧版本进行添加,但无济于事。

任何帮助都非常非常感谢。

标签: javaspringspring-bootspring-mvctomcat

解决方案


如评论中所述,问题来自jackson-dataformat-smile系统管理员放入 Tomcat 的类路径中的库。

如果您真的无法摆脱它,您可以使用以下三种解决方案之一:

  1. 将库添加到您的项目依赖项中(它将覆盖 Tomcat 的类路径中的那个),

  2. 禁用MappingJackson2SmileHttpMessageConverter: 不像之前所说的那样,SmileFactory不会被检测到,但如果它在其类路径上检测到工厂(参见) ,则由 Spring显式ServiceLoader调用。这是通过将库添加到类路径中“神奇地”出现的特性的代价。WebMvcConfigurationSupport #addDefaultMessageConverters

    幸运的是,您可以覆盖默认消息转换器:只需添加 aWebMvcConfigurer并覆盖其configureMessageConverters. 你甚至可以在@SpringBootApplication课堂上做到这一点:

    @SpringBootApplication
    public class YourSpringApplication implements WebMvcConfigurer {
    
        @Override
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            // add configuration here
        }
    
        ...
    }
    

    您可以复制上述的部分内容addDefaultMessageConverters

  3. 通过添加到您的上下文文件来更改类加载器的搜索顺序(参见关于如何执行此操作并更改加载器属性的文档:delegate

    <Context>
        <Loader delegate="true" />
        ...
    </Context>
    

推荐阅读