Java 程序中 MongoDB 和 PostgreSQL 的 SOCKS 代理配置避坑指南

今天花了好几个小时研究如何在 Java 程序中通过 SOCKS 代理连接 MongoDB Atlas 和 PostgreSQL 数据库。

起初直接问了 Gemini,结果它“傻乎乎”地给了一堆过时甚至错误的建议。它一直在 HTTP Proxy、Socket 超时时间这些配置上绕圈子,完全没有自动去搜索最新的资讯,导致我浪费了大量时间。

事实证明,遇到这类具体驱动的配置问题,直接查阅最新的官方文档或社区讨论才是正道

MongoDB Atlas 的正确配置

最终在 MongoDB 官方文档中找到了解决方案:Connect to MongoDB with a SOCKS5 Proxy

现在的 MongoDB Java Driver 直接支持在连接字符串(Connection String)或 MongoClientSettings 中指定代理,非常方便。

方法:修改连接字符串

直接在 URL 后面追加 proxyHost 等参数即可,无需折腾 JVM 全局设置:

1
2
3
4
5
6
7
String connectionString = "mongodb+srv://user:[email protected]/?" +
"proxyHost=127.0.0.1" +
"&proxyPort=1080" +
"&proxyUsername=myProxyUser" + // 可选
"&proxyPassword=myProxyPass"; // 可选

MongoClient mongoClient = MongoClients.create(connectionString);

或者使用 MongoClientSettings Builder:

1
2
3
4
5
6
7
MongoClientSettings.builder()
.applyToSocketSettings(builder ->
builder.applyToProxySettings(proxyBuilder ->
proxyBuilder.host("127.0.0.1").port(1080)
)
)
.build();

PostgreSQL 的配置

PostgreSQL JDBC 驱动的处理方式则不同。查阅官方文档发现,它没有直接提供类似 MongoDB 那样的 proxyHost 快捷参数,而是提供了两种层级的解决方案:

方法一:全局 JVM 代理(简单,但影响全局)

PostgreSQL JDBC 驱动底层使用的是 Java 标准 Socket,因此它默认遵循 JVM 的系统网络配置。

在启动 Java 应用时添加参数:

1
java -DsocksProxyHost=127.0.0.1 -DsocksProxyPort=1080 -jar my-app.jar

或者在代码初始化阶段设置:

1
2
System.setProperty("socksProxyHost", "127.0.0.1");
System.setProperty("socksProxyPort", "1080");

这种方式最简单,但副作用是全局的:JVM 内所有使用默认 Socket 的网络连接(包括 HTTP 请求等)都会走这个代理。

方法二:自定义 SocketFactory(隔离,但需编码)

如果只想让 PostgreSQL 连接走代理而不影响其他组件,可以使用 JDBC URL 中的 socketFactory 参数。但这需要自己实现一个简单的 javax.net.SocketFactory 类。

  1. 实现 SocketFactory:创建一个类(如 SocksSocketFactory),在 createSocket 方法中显式使用 new Socket(Proxy)
  2. 配置连接字符串:在 URL 中指定该类名。
    jdbc:postgresql://host:port/db?socketFactory=com.example.MySocksSocketFactory

虽然稍微麻烦一点,但这才是生产环境中实现连接级隔离的正解。

总结

这次经历最大的教训是:AI 在处理通用逻辑时很强,但在涉及特定驱动版本的具体配置参数时,受限于训练数据的时间截止点,很容易提供过时信息,或者因为不知道最新特性而产生幻觉。

  • MongoDB: 查官方文档,用 Driver 自带参数(局部生效,推荐)。
  • PostgreSQL: 查官方文档参数列表,发现需用 socketFactory 实现局部代理,或退守 JVM 全局代理。

文档 > AI,切记。