質問は簡単です。 SOCKS 対応のソケット実装が、抽象クラスの実装のデフォルトの選択肢であるのはなぜですか? java.net.Socket 素朴に私は期待していjava.net.PlainSocketImplます。
背景はもう少し複雑です。
私はGLASSFISH-12213を殺そうとしています(または実際に回避しようとしています)。バグ自体の詳細はあまり重要ではありません。スレッド セーフではないネイティブ ライブラリがあり、GlassFish で作成された LDAP レルムからそれを同時に使用すると、JVM がクラッシュします。
それを回避するために、私は逆方向に作業を始めました: そもそもネイティブ ライブラリが呼び出されないようにすることはできますか? これにより、さまざまな理由で、特定の URI に対して適切なプロキシを見つける (またはしない) ことsun.net.spi.DefaultProxySelectorを担当するを調べました。ネイティブ メソッド呼び出しを行う場所がそこにあり、そこで JVM クラッシュが発生します。もし私がその電話を避けることができれば、私は仕事をしていただろう.
sun.net.spi.NetProperties.getBoolean("java.net.useSystemProxies")その呼び出しを回避できる 1 つの方法は、値がfalseであることを確認できる場合です。その場合、先ほど述べたネイティブ メソッドは呼び出されません。 falseがデフォルトであり、この点に関しては何も変更していません。
(つまり、実際にそうです。私がバグを観察したマシンで実行されている GlassFish インスタンスで明らかに証明されています。したがって、このコードがどのようにしてネイティブ ライブラリをまだロードしている可能性があるのか はわかりません。それは別の日の話題です。 .)
それで、そのパスをパントして、さらにバックアップしました:呼び出しでどのプロトコルが渡されURI schemeましたか? DefaultProxySelector.select(uri)たぶん、私はどういうわけか愚かなことに影響を与えて、そのネイティブコールをスキップすることができます.
結局のところ、プロトコルはsocket(おそらく のようなものだと思っていましたが、そうではldapありませんでした)。この事実と私の反証された仮定は、LDAP-realm-land のどこかで直接ソケットが手動で開かれていることを示唆していました (つまり、HttpUrlConnectionまたは他の抽象化のようなものを使用していません)。案の定、Sun が作成した LDAP-JNDI ブリッジはまさにこれを行います。渡される URI はsocket://somehost:389.
したがって、これらすべてから、プロキシ情報を設定していない、何も構成していない、または直接のデフォルトを使用する以外のことをしていないにもかかわらず、JDK が SOCKS プロキシを使用しようとしていることがわかります。 詳細については、 364 行目あたりのsetImpl()メソッドをjava.net.Socket参照し、トレースしてください。SocksSocketImpl.java
(これは、システム プロパティをミックスに追加するだけで、このコードパス全体をスキップできる可能性があることを最終的に示唆していますsocksNonProxyHosts=*。うわあ、その動作がデフォルトであってはなりませんか?)
その結果、また、私や GlassFish による構成の変更がないにもかかわらずDefaultProxySelector、なんらかの理由で のhasSystemProxiesフィールドが に設定されていると信じてtrue、さまざまな Sun LDAP 接続によって作成されたさまざまなソケットがネイティブ ルックアップを引き起こしています。 SOCKS プロキシ サーバー用。それは私だけかもしれませんが、それは狂気のように私を襲います.
では、これを読んでいる人なら誰でも、おそらく JDK チームに所属している、あるいは JDK チームに所属している人を知っている、またはここで歴史を知っている人は、 のデフォルトの実装がjava.net.Socket常に SOCKS プロキシを探す理由を知っていますか?
更新:答えは次のようになることがわかります。システムプロキシがどこかに設定されていて、SOCKS が有効になっている場合、すべてのものはそれを通過します。しかし、 のデフォルト値がjava.net.useSystemProxiesそのままfalseである場合、(デフォルトで) SOCKS プロキシを探すポイントは何ですか?