-Djava.net.preferIPv4Stack=true,强制IPv4 协议进行网络通信

报错场景:Java启动连接数据库:Permission denied: connect DualStackPlainSocketImpl

报错解读:是 JDK8 IPv6 双栈兼容经典权限报错,Windows 默认优先走 IPv6 协议栈去连 IPv4 数据库地址,系统安全策略直接拒绝了跨协议出站连接,并非数据库服务不可达、账号密码错误

常见场景

  1. 服务器同时开启 IPv4/IPv6,Java 默认会优先解析绑定 IPv6,导致:
    • 只能监听 [::]:端口,外部 IPv4 客户端连不上
    • 数据库、Redis、Nacos、MQ 等连接超时、地址解析异常
  2. 内网环境只配置了 IPv4 DNS,IPv6 解析失败
  3. 部分中间件不兼容 IPv6 监听地址

解决方案:添加系统全局环境变量(重启终端、IDEA、服务后生效)

  • 变量名:JAVA_TOOL_OPTIONS
  • 变量值:-Djava.net.preferIPv4Stack=true

作用 :JVM 启动参数,强制让 Java 应用优先使用 IPv4 协议进行网络通信,禁用默认优先 IPv6 的行为。

也可以每个用到的地方单独配置(请自行查找配置方法),如IDEA 开发环境:

Run/Debug Configurations → VM options 填入:-Djava.net.preferIPv4Stack=true

原理说明

  • Linux、Windows 现代系统默认双栈(IPv4+IPv6)
  • Java 从某个版本开始默认优先 IPv6 地址解析
  • 设置该参数后:
    • InetAddress.getLocalHost() 返回 IPv4 地址

    • 服务默认监听 0.0.0.0:端口(IPv4 通配地址)

    • 域名解析优先返回 A 记录(IPv4),不再优先 AAAA(IPv6)

系统全局环境变量优点

  • 所有 Java 程序(IDEA、Maven、Tomcat、Jar、第三方中间件)自动带上该参数,不用每个项目单独配置;
  • 彻底解决本机所有 Java 服务优先 IPv6 导致的内网访问、注册中心、数据库连接异常问题。

系统全局环境变量缺点

  • 全局生效,无法针对某个 Java 进程例外 如果以后有应用需要使用 IPv6,必须删掉这个环境变量,或者在启动命令手动覆盖参数:

    java -Djava.net.preferIPv4Stack=false -jar xxx.jar

  • 必须重启对应应用 / 终端才能加载环境变量,已经启动的 Java 进程不会自动生效。重要避坑点:

  1. 不要用普通自定义环境变量(比如 JAVA_OPTS) 自己定义的 JAVA_OPTS 系统不会自动被 JVM 读取,只有 JAVA_TOOL_OPTIONS 是 JVM 专属全局环境变量才能自动加载。

  2. 代码里 System.setProperty("java.net.preferIPv4Stack","true") 依然可能失效 如果网络相关类(InetAddress)在代码执行前就被类加载器加载,代码设置会无效,用 JAVA_TOOL_OPTIONS 方式最稳妥。

  3. 多个 JVM 参数写法示例

    JAVA_TOOL_OPTIONS="-Djava.net.preferIPv4Stack=true -Xms512m -Xmx1024m"