注意 追記 2014/03/17
この記事で紹介した問題回避方法は処理系依存かもしれません。Windows版JDK7(Oracle)のクライアントモードJVMでは意図通りに動作したもののLinux版JDK7(Oracle)のサーバモードJVMで依然として問題動作(WSDLを実行時に参照してしまう)が見られました。詳しい検証ができていませんが、この技法を利用する場合開発環境・動作環境両方でのチェックをお願いします。さてそのJAX-WS、控えめに言ってもとても残念な子です。
個人的には、プロキシコードを静的に生成する点やプロキシコードが中途半端にWSDLを参照している点が、そもそも仕様としてイケテナイと思っています。(プロキシコードを生成するくらいなら、WSDLを参照しないで欲しいですね。)
JAX-WS仕様は、イケテナイ | OPENSQUARE.jp - BLOG
WSDLとはWebサービスのインターフェース仕様を記述したXML文書です。クライアント側のプロキシコードを自動生成するのにWSDLが必要なのは当たり前です。しかしJAX-WSの生成したプロキシコードは、実行時にもう一度WSDLを読みに行くんです。
なぜ実行時にWSDLなんか必要なのか。WSDLにはインターフェース仕様のほかに、アクセス先URLも書いてあるからです。それだけ。本当にそれだけ。だったらアクセス先URLを直接指定させてくれればいいことじゃない!?
繰り返します。JAX-WSは控えめに言っても本当に本当に残念な子なんです。
アクセス先URLだけのためにWSDLをいちいち読みに行かれるんじゃオーバーヘッドだってソケット数リソース消費だって重いし、そもそもWSDLが必ず読めるとは限りませんよ? IEEE1888みたいに規格としてWebサービスインターフェースが決まっているサービスの場合、アクセスURLだけわかっててWSDLのURLはわからないなんてことざらです*1。
目的のアクセス先URLを埋め込んだテンポラリWSDLを生成して file:///... 形式のURLで読ませちゃいなよって? 断る。なんでこんなことのためにI/O負荷増やさなきゃならんの…
はい、解決法。
まず、プロキシファクトリを作るときに、WSDLのURLとして無慈悲にnullを食わせます。
EchoService echoService = new EchoService(null); // WSDL locationは… null…っ! EchoServicePortType proxyObj = echoService.getEchoServiceSOAP11PortHttp();
このままではプロキシオブジェクトは(WSDLが読めなかったせいで)アクセス先URLを知りません。
強引に教え込みましょう。
((BindingProvider) proxyObj).put(
BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
"http://アクセス先URL");