添加测试环境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上下文被初始化两次:
- 第一次是
main方法中启动的上下文 - 第二次是
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
相关产品推荐
相关产品推荐

