问题很简短。 为什么 SOCKS 感知套接字实现是抽象java.net.Socket
类实现的默认选择? 我天真地期待着java.net.PlainSocketImpl
。
背景稍微复杂一些。
我正在尝试杀死GLASSFISH-12213(或者我真的在尝试解决它)。错误本身的细节并不是很重要——有一个本地库不是线程安全的,并且来自 GlassFish 创作的 LDAP 领域的一些并发使用会导致 JVM 崩溃。
为了解决这个问题,我开始向后工作:我可以避免首先调用本机库吗?这导致我出于各种原因查看sun.net.spi.DefaultProxySelector
,它负责为给定的 URI 找到一个合适的代理(或不)。那里有一个地方可以进行本地方法调用,这就是 JVM 崩溃发生的地方。如果我能避免那个电话,我会做生意的。
我可以避免该调用的一种方法是,如果我可以确保sun.net.spi.NetProperties.getBoolean("java.net.useSystemProxies")
false 的值。如果是这样,那么我之前提到的本地方法就不会被调用。 false
是默认设置,我根本没有在这方面进行任何修改。
(实际上就是这样;在我观察到该错误的那台机器上运行的 GlassFish 实例中得到了证明。因此,我不确定这段代码如何仍可能加载本机库;这是另一天的主题.)
所以,在这条道路上,我进一步支持:URI
scheme
在DefaultProxySelector.select(uri)
调用中传递了什么协议?也许然后我可以以某种方式影响愚蠢的事情,以某种方式仍然跳过该本地调用。
事实证明,协议是socket
(我曾假设它可能类似于ldap
,但不是)。这个事实和我被证明的假设向我表明,LDAP-realm-land 中的某个地方正在手动打开一个直接套接字(即不使用类似 anHttpUrlConnection
或其他抽象的东西)。果然,Sun 创作的 LDAP-JNDI 桥接器就是这样做的。传入的 URI 是socket://somehost:389
.
因此,尽管事实上我没有设置任何代理信息,没有配置任何东西或做任何事情,除了使用直接默认值之外,从这一切来看,事实证明JDK 尝试使用 SOCKS 代理。 有关详细信息,请参阅第setImpl()
java.net.Socket
364 行左右的SocksSocketImpl.java
方法并对其进行跟踪。
(这最终表明我可以通过简单地将socksNonProxyHosts=*
系统属性添加到组合中来跳过整个代码路径。天哪,这种行为不应该是默认行为吗?)
结果——再一次相信,尽管我或 GlassFish 没有更改配置,但DefaultProxySelector
由于某种原因将其hasSystemProxies
字段设置为,true
由花园品种 Sun LDAP 连接创建的花园品种套接字导致本机查找用于 SOCKS 代理服务器。也许这只是我,但这让我觉得很疯狂。
那么有没有人读过这篇文章——也许你在 JDK 团队,或者认识某个人,或者知道这里的历史——知道为什么java.net.Socket
总是寻找 SOCKS 代理的默认实现?
更新:我可以看到答案是:因此,如果您在某处设置了系统代理,并且它启用了 SOCKS,则所有内容都会通过它。但是,如果默认值java.net.useSystemProxies
是false
,那么对于 SOCKS 代理进行搜索(默认情况下)有什么意义呢?