Spring Boot Maven项目添加spring-mock依赖后启动失败问题排查
免责声明:我并非JVM领域专家,对Maven、Spring相关框架的使用经验有限,若存在明显疏漏还请谅解。
项目背景
我接手了一个Java+Kotlin混合开发的Spring Boot Maven项目,未添加spring-mock时的原始pom.xml配置附在问题末尾。
遇到的问题
在项目中添加如下spring-mock依赖后:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-mock</artifactId> <version>2.0.8</version> </dependency>
应用启动时直接报错,错误信息如下:
*************************** 应用启动失败 *************************** 问题描述: 程序尝试调用一个不存在的方法,调用来源为: org.apache.catalina.authenticator.AuthenticatorBase.startInternal(AuthenticatorBase.java:1321) 缺失的方法定义为: javax.servlet.ServletContext.getVirtualServerName()Ljava/lang/String; 该方法所属的`javax.servlet.ServletContext`类可从以下两个位置找到: jar:file:/home/atrauzzi/.m2/repository/javax/servlet/servlet-api/2.3/servlet-api-2.3.jar!/javax/servlet/ServletContext.class jar:file:/home/atrauzzi/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/9.0.35/tomcat-embed-core-9.0.35.jar!/javax/servlet/ServletContext.class 实际被加载的类来源为: file:/home/atrauzzi/.m2/repository/javax/servlet/servlet-api/2.3/servlet-api-2.3.jar 官方提示的处理方向: 修正应用的类路径配置,确保类路径中只存在一个兼容版本的`javax.servlet.ServletContext`
未添加spring-mock时的原始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.3.0.RELEASE</version> <relativePath/> </parent> <groupId>com.myproject</groupId> <artifactId>pdf-things</artifactId> <version>0.0.1-development</version> <name>pdf-things</name> <description>PDF Things</description> <properties> <java.version>1.8</java.version> <maven.test.skip>true</maven.test.skip> <kotlin.version>1.3.72</kotlin.version> <kotlin.compiler.progressive>true</kotlin.compiler.progressive> </properties> <repositories> <repository> <id>AsposeJavaAPI</id> <name>Aspose Java API</name> <url>https://artifact.aspose.com/repo/</url> </repository> <repository> <id>central</id> <name>Maven Central</name> <url>https://repo1.maven.org/maven2</url> </repository> </repositories> <dependencies> <dependency> <groupId>com.itextpdf</groupId> <artifactId>html2pdf</artifactId> <version>3.0.3</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext7-core</artifactId> <version>7.1.13</version> <type>pom</type> </dependency> <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> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.aspose</groupId> <artifactId>aspose-pdf</artifactId> <version>19.12</version> </dependency> <dependency> <groupId>com.aspose</groupId> <artifactId>aspose-words</artifactId> <version>19.1</version> <classifier>jdk16</classifier> </dependency> <dependency> <groupId>com.aspose</groupId> <artifactId>aspose-imaging</artifactId> <version>17.9</version> <classifier>jdk16</classifier> </dependency> <dependency> <groupId>com.aspose</groupId> <artifactId>aspose-cells</artifactId> <version>19.1</version> </dependency> <dependency> <groupId>com.aspose</groupId> <artifactId>aspose-cells</artifactId> <version>19.1</version> <classifier>javadoc</classifier> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk16</artifactId> <version>1.46</version> </dependency> <dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>7.0.1</version> </dependency> <dependency> <groupId>com.azure</groupId> <artifactId>azure-storage-blob</artifactId> <version>12.6.0</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib-jdk8</artifactId> <version>${kotlin.version}</version> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-test</artifactId> <version>${kotlin.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-webmvc-core</artifactId> <version>1.3.9</version> </dependency> <dependency> <groupId>io.swagger.core.v3</groupId> <artifactId>swagger-annotations</artifactId> <version>2.1.2</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-plugin</artifactId> <version>${kotlin.version}</version> <executions> <execution> <id>compile</id> <phase>compile</phase> <goals> <goal>compile</goal> </goals> </execution> <execution> <id>test-compile</id> <phase>test-compile</phase> <goals> <goal>test-compile</goal> </goals> </execution> </executions> <configuration> <jvmTarget>1.8</jvmTarget> <compilerPlugins> <plugin>no-arg</plugin> </compilerPlugins> <pluginOptions> <option>no-arg:annotation=com.my.Annotation</option> </pluginOptions> </configuration> <dependencies> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-noarg</artifactId> <version>${kotlin.version}</version> </dependency> </dependencies> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>${java.version}</source> <target>${java.version}</target> </configuration> <executions> <execution> <id>default-compile</id> <phase>none</phase> </execution> <execution> <id>default-testCompile</id> <phase>none</phase> </execution> <execution> <id>java-compile</id> <phase>compile</phase> <goals> <goal>compile</goal> </goals> </execution> <execution> <id>java-test-compile</id> <phase>test-compile</phase> <goals> <goal>testCompile</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
问题根因
报错本质是类路径中存在两个版本不兼容的javax.servlet.ServletContext实现,高优先级加载的旧版本破坏了运行时类兼容性:
- 你引入的
spring-mock:2.0.8是2007年发布的已废弃版本,它本身传递依赖了javax.servlet:servlet-api:2.3——这是符合20年前Servlet 2.3规范的API版本,根本不包含getVirtualServerName()方法(该方法是Servlet 3.1版本后才新增的)。 - 项目基于Spring Boot 2.3.0构建,内置Tomcat 9对应Servlet 4.0规范,
tomcat-embed-core包自带符合Servlet 4.0标准的ServletContext类。 - Maven类加载规则下,旧版本的
servlet-api-2.3.jar优先被加载,导致Tomcat启动时调用新版ServletContext的方法时,实际拿到的是旧版本类的实例,触发方法不存在的报错。
修复方案
- 最优方案:直接移除
spring-mock:2.0.8依赖
这个老包的全部功能早在2007年就已经合并到spring-test模块中,项目通过spring-boot-starter-test已经引入了兼容当前Spring Boot版本的完整spring-test,原spring-mock提供的所有测试模拟能力都可以直接使用,完全不需要额外引入这个过期依赖。 - 如果有特殊原因必须保留这个老旧依赖,需要在依赖配置中排除它传递引入的旧版Servlet API:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-mock</artifactId> <version>2.0.8</version> <exclusions> <exclusion> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> </exclusion> </exclusions> </dependency>
内容的提问来源于stack exchange,提问作者Alexander Trauzzi
相关产品推荐
相关产品推荐

