阅读 JAX-WS 2.2 规范,第 4 章:客户端 API。
1.静态客户端生成
确实是使用 JAX-WS 的最简单方法。从 Web 服务的角度来看,WSDL 是接口和连接属性。即使您选择不实际使用它,您仍然需要从逻辑意义上了解它才能进行有意义的 SOAP 调用。
来自 JAX-WS 规范的注释:使用 SOAP 1.1/HTTP 绑定的端点必须在发布地址以 WSDL 1.1 文档的形式提供其合同,并以?WSDL
或为后缀?wsdl
2.动态客户端编程
有没有办法在我的代码中注入一个由应用程序服务器管理的动态代理?
此方法涉及针对 JAX-WS API 的动态编程,以使用或不使用 WSDL 连接到 Web 服务。没有办法随便“注入”一个动态代理。您需要使用 SEI 的端口 URL 构建和配置一个。WSDL 文档是存储此类配置信息的标准位置,尽管可以避免它并以编程方式插入信息。
2A) 使用 WSDL 进行动态编程:
javax.xml.ws.Service service = Service.create(
new URL("http://example.org/stocks.wsdl"),
new QName("http://example.org/stocks", "StockQuoteService"));
com.example.StockQuoteProvider proxy = service.getPort(portName,
com.example.StockQuoteProvider.class)
javax.xml.ws.BindingProvider bp = (javax.xml.ws.BindingProvider)proxy;
Map<String,Object> context = bp.getRequestContext();
context.setProperty("javax.xml.ws.session.maintain", Boolean.TRUE);
proxy.getLastTradePrice("ACME");
优于 (1) 的优点:可以在应用部署后动态更改 WSDL 文档,前提是此类更改不会影响到客户端的 java 接口。
即对你几乎没有什么好处。您的 WSDL 是静态的。虽然您可以将您的客户端指向<service endpoint URL>?wsdl
动态查找,但这意味着您需要手动配置<service endpoint URL>
AND,在不影响您的客户端逻辑的情况下,在 SEI/WSDL 中几乎没有其他可以更改的内容。
2B) 没有 WSDL 的动态编程:
String endpointUrl = ...;
QName serviceName = new QName("http://example.org/wssample/echo/", "EchoService");
QName portName = new QName("http://example.org/wssample/echo/", "EchoServicePort");
/** Create a service and add at least one port to it. **/
Service service = Service.create(serviceName);
service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, endpointUrl);
/** Create a Dispatch instance from a service.**/
Dispatch<SOAPMessage> dispatch = service.createDispatch(portName,
SOAPMessage.class, Service.Mode.MESSAGE);
/** Create SOAPMessage request. **/
// compose a request message
MessageFactory mf = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
// Create a message. This example works with the SOAPPART.
SOAPMessage request = mf.createMessage();
SOAPPart part = request.getSOAPPart();
// Obtain the SOAPEnvelope and header and body elements.
SOAPEnvelope env = part.getEnvelope();
SOAPHeader header = env.getHeader();
SOAPBody body = env.getBody();
// Construct the message payload.
SOAPElement operation = body.addChildElement("invoke", "ns1",
"http://com/ibm/was/wssample/echo/");
SOAPElement value = operation.addChildElement("arg0");
value.addTextNode("ping");
request.saveChanges();
/** Invoke the service endpoint. **/
SOAPMessage response = dispatch.invoke(request);
优势(不是真的):最终可以让它执行与上述相同的行为。
缺点:编程复杂。非标准配置(WSDL 之外)。需要避免硬编码设置。易受界面变化影响。在服务器和客户端之间手动同步设置 - 容易忽略某些东西,调试起来非常困难。
回答:
回到(1)。从 WSDL 生成客户端存根。将其用作接口契约——它应该设计得好而不是改变。
然后花时间解决实际问题... ;) ;)