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

添加测试环境application.properties后SpringBootTest报8080端口占用错误

解决Spring Boot测试时Port 8080被占用的问题

为避免测试占用PostgreSQL连接,我们在src/test/resources下创建独立的application.properties切换到H2内存数据库,配置如下:

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.generate-ddl=false
spring.jpa.hibernate.ddl-auto=none
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.liquibase.enabled=false
spring.liquibase.change-log=
security.oidc_domain=123
security.jwt_key=123
api_url=http://localhost:8080
encryption.secret=123
security.debug=false
allowed_hosts=*

项目启动类代码:

@SpringBootApplication
@EnableScheduling
public class CoreApplication implements CommandLineRunner {

    public static void main(final String[] args) {
        SpringApplication application = new SpringApplication(CoreApplication.class);
        application.run(args);
    }

    public ConfigurableApplicationContext context;

    @Override
    public void run(final String... args) throws Exception {
        System.out.println(args);
        context = SpringApplication.run(CoreApplication.class, args);
    }

}

测试类代码:

@SpringBootTest()
class CoreApplicationTests {
    @Test()
    void contextLoads() {
    }
}

运行测试时出现端口占用错误:

Caused by: org.springframework.context.ApplicationContextException: Failed to start bean 'webServerStartStop'; nested exception is org.springframework.boot.web.server.PortInUseException: Port 8080 is already in use
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181) ~[spring-context-5.3.22.jar:5.3.22]
    at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) ~[spring-context-5.3.22.jar:5.3.22]
    at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356) ~[spring-context-5.3.22.jar:5.3.22]
    at java.base/java.lang.Iterable.forEach(Iterable.java:75) ~[na:na]

添加测试配置前测试正常,怀疑是测试配置引发问题。


问题根源

你的CoreApplication实现了CommandLineRunner,但在run方法中又调用了SpringApplication.run(CoreApplication.class, args),这会导致Spring上下文被初始化两次:

  1. 第一次是main方法中启动的上下文
  2. 第二次是CommandLineRunner的run方法中再次启动的上下文

两次启动都会尝试绑定8080端口,第二次启动时端口已被第一次占用,因此抛出PortInUseException。之前测试未暴露该问题,只是因为环境未触发完整冲突逻辑,本质是启动类代码错误。

解决方案

修改CoreApplication的run方法,移除重复的SpringApplication.run调用。CommandLineRunner的run方法是在Spring上下文启动完成后执行的,无需再次启动上下文:

@SpringBootApplication
@EnableScheduling
public class CoreApplication implements CommandLineRunner {

    public static void main(final String[] args) {
        SpringApplication.run(CoreApplication.class, args);
    }

    @Override
    public void run(final String... args) throws Exception {
        System.out.println(args);
        // 无需再次调用SpringApplication.run
    }

}

如果需要在CommandLineRunner中获取上下文,可以调整为:

@SpringBootApplication
@EnableScheduling
public class CoreApplication implements CommandLineRunner {

    private ConfigurableApplicationContext context;

    public static void main(final String[] args) {
        ConfigurableApplicationContext ctx = SpringApplication.run(CoreApplication.class, args);
        CoreApplication app = ctx.getBean(CoreApplication.class);
        app.context = ctx;
    }

    @Override
    public void run(final String... args) throws Exception {
        System.out.println(args);
        // 可通过this.context操作上下文
    }

}

额外优化(可选)

在测试配置文件src/test/resources/application.properties中添加随机端口配置,彻底避免端口冲突:

server.port=0

配置server.port=0后,Spring Boot会自动分配未被占用的随机端口,更适合测试环境使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 17:01:24