wsl的网络导致springboot启动提示端口占用

WSL2 + Docker 环境下 SpringBoot 启动端口被占用的诡异问题排查

在本地开发环境中,我遇到了一个非常"玄学"的问题:SpringBoot 服务启动时提示 48080 端口被占用,但服务销毁后端口又立刻释放

更离谱的是,有时候启动失败,再次启动却又完全正常

经过排查,最终发现问题与 WSL2 网络模式 + Docker 端口映射 + Redis 容器连接有关。本文把完整排查过程记录下来,供遇到类似问题的人参考。


一、问题现象

项目环境:

  • 开发系统:Windows 11 + WSL2
  • Java:JDK8
  • SpringBoot
  • Redis:Docker 容器
  • RocketMQ / RabbitMQ / Kafka 等中间件
  • 运行方式:SpringBoot 本地运行,Redis 在 WSL 的 Docker 容器中

启动 SpringBoot 时,出现异常:

复制代码
Bind for :::48080 failed: port is already allocated

查看端口占用:

复制代码
lsof -i:48080

输出:

复制代码
docker-pr 16508 root  TCP *:48080 (LISTEN)
docker-pr 16516 root  TCP *:48080 (LISTEN)

但是当 SpringBoot 启动失败后,再查看端口:

复制代码
lsof -i:48080

端口又消失了。

也就是说:

时间 状态
启动瞬间 端口被占用
服务退出 端口释放
再次启动 有时正常

表现为 "端口占用,但又不是持续占用"


二、最终解决方案

经过排查后,最终的解决方法是:

不要连接 WSL 内 Docker 容器的 localhost Redis。

原来我的 Redis 是:

复制代码
WSL2
 └── docker
      └── redis:6379

SpringBoot 配置:

复制代码
spring.redis.host=127.0.0.1
spring.redis.port=6379

后来我把 Redis 改成 另一台服务器上的 Docker Redis

复制代码
spring.redis.host=192.168.x.x
spring.redis.port=6379

然后:

复制代码
项目启动完全正常

之后再切换回来,竟然 偶尔也可以正常启动

这说明问题并不是代码问题,而是 WSL 网络瞬态状态问题


三、问题原因分析

这个问题本质上是:

WSL2 Mirror 网络 + Docker 端口代理 + Redis 启动时序竞争(race condition)

完整调用链大致如下:

复制代码
SpringBoot
   ↓
Redis Client (Lettuce / Netty)
   ↓
127.0.0.1:6379
   ↓
WSL2 Mirror Network
   ↓
docker-proxy
   ↓
Redis Container

这里面涉及多个网络层:

复制代码
SpringBoot
WSL 虚拟网络
Docker bridge
docker-proxy
iptables
Redis container

只要其中一个 未 ready,就会出现问题。


四、为什么会出现"端口占用"

SpringBoot 启动流程大致如下:

复制代码
1 Bean 初始化
2 RedisClient 初始化
3 MQ 初始化
4 WebServer (Tomcat) 启动

如果 Redis 初始化失败:

复制代码
Redis connect fail
↓
Spring Context Exception
↓
ApplicationContext destroy
↓
Tomcat stop
↓
端口释放

但是日志顺序会变成:

复制代码
Tomcat started
Port already in use
ApplicationContextException

看起来就像:

复制代码
48080 被占用了

实际上:

真正失败的是 Redis 连接。


五、为什么第二次启动又好了

这种现象在 WSL + Docker 中非常常见。

可能原因:

1 Redis 容器刚启动

Redis 可能:

复制代码
6379 已监听
但服务还没 ready

第一次连接失败,第二次成功。


2 docker-proxy 还未建立端口映射

Docker 端口映射:

复制代码
host:6379
↓
docker-proxy
↓
container:6379

docker-proxy 在某些情况下 需要几百毫秒建立规则


3 WSL2 Mirror 网络初始化

WSL2 的 Mirror 网络会涉及:

复制代码
vEthernet
iptables
bridge

第一次访问可能触发规则创建。


六、如何避免这种问题

推荐以下三种方式。


方案1:服务全部 Docker 化(最稳定)

复制代码
docker compose
 ├── springboot
 ├── redis
 ├── mysql
 ├── kafka

SpringBoot 连接:

复制代码
spring.redis.host=redis

直接通过 Docker Network。


方案2:Redis 放 Windows Docker Desktop

结构:

复制代码
Windows Docker
   └── Redis
WSL SpringBoot

SpringBoot:

复制代码
localhost:6379

稳定性会比 WSL Docker 高。


方案3:增加连接重试

例如 Redis 连接:

复制代码
retry
wait-for-it
healthcheck

Docker Compose:

复制代码
depends_on:
  redis:
    condition: service_healthy

七、总结

这个问题看起来像:

复制代码
SpringBoot 端口占用

但实际上是:

复制代码
WSL2 网络
+
Docker 端口代理
+
Redis 服务启动时序

三者叠加导致的 瞬态连接问题

典型现象就是:

复制代码
第一次启动失败
第二次启动成功

如果你在 WSL + Docker + SpringBoot 环境中遇到类似问题,优先检查:

  • Redis / MySQL / Kafka 是否 ready
  • docker-proxy 端口映射
  • WSL 网络模式
  • localhost 连接路径

很多时候问题并不在代码,而在 开发环境网络架构

相关推荐
xiaoye37082 小时前
Spring如何处理线程并发问题
java·后端·spring
梦白.2 小时前
初始计算机网络
网络·计算机网络
爱丽_2 小时前
博客:Netty 高性能网络编程核心(Reactor / Pipeline / 粘拆包 / ByteBuf / 背压)
网络
前端付豪2 小时前
拍照识题 OCR
前端·后端·python
Chan162 小时前
LeetCode 热题 100 | 链表
java·数据结构·spring boot·算法·leetcode·链表·java-ee
weixin_704266052 小时前
[特殊字符] Spring IOC/DI 核心知识点 CSDN 风格总结
java·后端·spring
常利兵2 小时前
Spring Boot 4.0 牵手RabbitMQ:注解魔法开启消息之旅
spring boot·rabbitmq·java-rabbitmq
拾贰_C2 小时前
[spring boot | springboot web ] spring boot web项目启动失败问题
前端·spring boot·后端
indexsunny2 小时前
互联网大厂Java面试实录:Spring Boot与微服务在电商场景中的应用解析
java·spring boot·面试·kafka·spring security·电商·microservices