You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 3升级后JUnit测试出现javax.servlet.Filter类找不到异常

问题:Spring Boot 3.0 + Java 17升级后JUnit测试报错javax.servlet.Filter找不到

我们原有基于Spring Boot 2.7.x、Java 11的应用,现计划升级至Spring Boot 3.0.0与Java 17。本地IntelliJ IDE完成修改后,运行如下JUnit测试类时出现异常:

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.assertTrue;

@SpringBootTest
class MyCompanyAppRegistrationApplicationTests {

    @Test
    void contextLoads() {
        assertTrue(true);
    }

}

错误信息:

java.lang.IllegalStateException: Failed to load ApplicationContext for [WebMergedContextConfiguration@55a66bbf 

testClass = company.registration.MyCompanyAppRegistrationApplicationTests, 
locations = [], 
classes = [company.registration.MyCompanyAppRegistrationApplication], 
contextInitializerClasses = [], activeProfiles = [], propertySourceLocations = [], 
propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], 
contextCustomizers = [org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@1e6cc850, 

                      org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@48b22fd4, 
                      org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, 
                      org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@178270b2, 
                      org.springframework.boot.test.autoconfigure.actuate.observability.ObservabilityContextCustomizerFactory$DisableObservabilityContextCustomizer@9da1, 
                      org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, 
                      org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@3d36dff4, 
                      org.springframework.boot.test.context.SpringBootTestAnnotation@3954286c], 
resourceBasePath = "src/main/webapp", contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, parent = null]
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Failed to process import candidates for configuration class [company.registration.MyCompanyAppRegistrationApplication]: Failed to load class [javax.servlet.Filter]
Caused by: java.io.IOException: Failed to load class [javax.servlet.Filter]
Caused by: java.lang.ClassNotFoundException: javax.servlet.Filter

已知Spring 3.x支持JakartaEE 9和10,已将所有需要的javax包替换为Jakarta.,但仍出现需要javax.servlet.Filter的情况。当前pom.xml配置如下:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.0.0</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <java.version>17</java.version>

    <commons-lib.version>3.2.1</commons-lib.version>
    <datasource-lib.version>1.4.0</datasource-lib.version>

    <wiremock.version>2.27.2</wiremock.version>
    <archunit.version>1.0.1</archunit.version>
    <guava.version>31.1-jre</guava.version>
    <h2.version>1.4.200</h2.version>
    <jakarta.validaton.api.version>3.0.0</jakarta.validaton.api.version>
</properties>

<dependencies>
    <!-- internal dependencies-->
    <dependency>
        <groupId>my company</groupId>
        <artifactId>commons-lib</artifactId>
        <version>${commons-lib.version}</version>
    </dependency>
    <dependency>
        <groupId>my company</groupId>
        <artifactId>datasource-lib</artifactId>
        <version>${datasource-lib.version}</version>
    </dependency>

    <!--PROVIDED-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.retry</groupId>
        <artifactId>spring-retry</artifactId>
    </dependency>
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>${guava.version}</version>
    </dependency>
    <dependency>
        <groupId>jakarta.validation</groupId>
        <artifactId>jakarta.validation-api</artifactId>
        <version>${jakarta.validaton.api.version}</version>
    </dependency>
    <dependency>
        <groupId>jakarta.persistence</groupId>
        <artifactId>jakarta.persistence-api</artifactId>
        <version>3.1.0</version>
    </dependency>


    <!--TEST-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.github.tomakehurst</groupId>
        <artifactId>wiremock</artifactId>
        <version>${wiremock.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>${h2.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-inline</artifactId>
        <version>${mockito.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.tngtech.archunit</groupId>
        <artifactId>archunit</artifactId>
        <version>${archunit.version}</version>
        <scope>test</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-source-plugin</artifactId>
            <executions>
                <execution>
                    <id>attach-sources</id>
                    <goals>
                        <goal>jar</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.sonarsource.scanner.maven</groupId>
            <artifactId>sonar-maven-plugin</artifactId>
            <version>3.8.0.2131</version>
        </plugin>
        <plugin>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <version>0.8.8</version>
            <configuration>
                <rules>
                </rules>
            </configuration>
            <executions>
                <execution>
                    <id>default-prepare-agent</id>
                    <goals>
                        <goal>prepare-agent</goal>
                    </goals>
                </execution>
                <execution>
                    <id>default-report</id>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>report</goal>
                    </goals>
                </execution>
                <execution>
                    <id>default-check</id>
                    <goals>
                        <goal>check</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

<distributionManagement>
    <repository>
        <id>central</id>
        <name>libs-staging-local</name>
        <url>https://some-url</url>
    </repository>
    <snapshotRepository>
        <id>snapshots</id>
        <name>libs-snapshot-local</name>
        <url>https://some-url</url>
    </snapshotRepository>
</distributionManagement>

<repositories>
    <repository>
        <id>azd-releases</id>
        <url>https://some-url</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>azd-snapshots</id>
        <url>https://some-url</url>
        <releases>
            <enabled>false</enabled>
        </releases>
    </repository>
    <repository>
        <id>apache-central</id>
        <url>https://repo.maven.apache.org/maven2/</url>
    </repository>
</repositories>

请问应从哪些方向排查该问题?是否需要检查pom.xml中的依赖?


排查方向及解决方案

1. 检查传递依赖中的旧javax.servlet包

Spring Boot 3.x完全切换到Jakarta EE规范,API前缀从javax.*改为jakarta.*,但传递依赖可能偷偷引入旧的javax.servlet相关包:

  • 执行mvn dependency:tree命令,搜索输出里的javax.servlet关键词,定位是哪个依赖引入了旧包。
  • 对引入旧包的依赖,要么升级到支持Jakarta EE的版本,要么在pom.xml中用<exclusions>排除掉javax.servlet相关依赖项。

2. 验证内部依赖的兼容性

pom.xml里的commons-lib和datasource-lib两个内部依赖大概率还停留在Spring Boot 2.x版本,依赖旧的javax.servlet API:

  • 确认这两个内部库是否已升级到支持Spring Boot 3.x和Jakarta EE的版本,没升级的话同步升级。
  • 暂时无法升级的话,给这两个依赖添加排除规则:
<dependency>
    <groupId>my company</groupId>
    <artifactId>commons-lib</artifactId>
    <version>${commons-lib.version}</version>
    <exclusions>
        <exclusion>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
        </exclusion>
    </exclusions>
</dependency>

3. 升级测试依赖版本

  • 你用的WireMock 2.27.2依赖旧的javax.servlet API,Spring Boot 3.x环境下必须升级到WireMock 3.x及以上版本(3.0+支持Jakarta EE)。
  • ArchUnit 1.0.1也存在兼容性问题,建议升级到支持Java 17和Jakarta EE的版本(比如1.2.0及以上)。

4. 确认Web Starter是否完整

如果你的应用是Web应用,检查是否引入了spring-boot-starter-web——Spring Boot 3.x的这个starter会自动引入jakarta.servlet-api,缺失的话手动添加:

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

5. 清理IDE缓存

IntelliJ可能残留旧依赖缓存,导致加载错误的类:

  • 执行mvn clean install清理本地构建产物。
  • 在IDE中通过File -> Invalidate Caches...清理缓存并重启。

内容的提问来源于stack exchange,提问作者Ivajlo Iliev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 11:05:54