|
Java Web Service的客戶端實現(xiàn)有三種
1. 生成的stub 2. 動態(tài)代理 3. 動態(tài)調(diào)用接口 其中生成stub是最常用的。stub是用JAX-RPC編譯器根據(jù)WSDL文檔生成的,其主要功能是將對endpoint接口的方法調(diào)用轉(zhuǎn)化為SOAP 消息,并且負責將返回的SOAP響應(yīng)轉(zhuǎn)換為方法的返回值,把SOAP fault轉(zhuǎn)化為方法的異常。JAX-RPC編譯器產(chǎn)生的stub除了要實現(xiàn)endpoint接口外,還需要實現(xiàn)或繼承 javax.xml.rpc.Stub接口或其實現(xiàn)的子類(Axis中是org.apache.axis.client.Stub)。 javax.xml.rpc.Stub接口主要定義了和網(wǎng)絡(luò)通訊和認證相關(guān)的屬性的設(shè)置和獲取的機制。 Java Web Service的客戶端實現(xiàn)有三種 1. 生成的stub 2. 動態(tài)代理 3. 動態(tài)調(diào)用接口 其中生成stub是最常用的。stub是用JAX-RPC編譯器根據(jù)WSDL文檔生成的,其主要功能是將對endpoint接口的方法調(diào)用轉(zhuǎn)化為SOAP 消息,并且負責將返回的SOAP響應(yīng)轉(zhuǎn)換為方法的返回值,把SOAP fault轉(zhuǎn)化為方法的異常。JAX-RPC編譯器產(chǎn)生的stub除了要實現(xiàn)endpoint接口外,還需要實現(xiàn)或繼承 javax.xml.rpc.Stub接口或其實現(xiàn)的子類(Axis中是org.apache.axis.client.Stub)。 javax.xml.rpc.Stub接口主要定義了和網(wǎng)絡(luò)通訊和認證相關(guān)的屬性的設(shè)置和獲取的機制。其代碼如下: package javax.xml.rpc; import java.util.Iterator; public interface Stub { // Standard property: The Web service‘s Internet address. public static String ENDPOINT_ADDRESS_PROPERTY; // Standard property: Password for authentication. public static String PASSWORD_PROPERTY; // Standard property: User name for authentication. public static String USERNAME_PROPERTY; // Standard property: Boolean flag for maintaining an HTTP session. public static String SESSION_MAINTAIN_PROPERTY; // Given a property name, get its value. public Object _getProperty(java.lang.String name); // Get the names of all the properties the stub supports. public Iterator _getPropertyNames(); // Configure a property on the stub. public void _setProperty(java.lang.String name, java.lang.Object value); } JAX-RPC編譯器產(chǎn)生還可以產(chǎn)生一個和WSDL中service元素對應(yīng)的Service接口,該接口組合了多個port,也就是多個Stub。該接口繼承了javax.xml.rpc.Service。在J2EE環(huán)境中Service接口通常通過JNDI lookup得到。 在J2EE中使用生成的stub的典型用例如下: 代碼: package com.jwsbook.jaxrpc; import javax.servlet.http.*; import javax.servlet.*; import javax.naming.InitialContext; public class BookQuoteServlet_1 extends javax.servlet.http.HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,java.io.IOException { try{ String isbn = req.getParameter("isbn"); InitialContext jndiContext = new InitialContext(); BookQuoteService service = (BookQuoteService) jndiContext.lookup("java:comp/env/service/BookQuoteService"); BookQuote bookQuote = service.getBookQuotePort(); float price = bookQuote.getBookPrice( isbn ); java.io.Writer outStream = resp.getWriter(); outStream.write("The wholesale price for ISBN:"+isbn+ " = "+price+""); }catch(javax.naming.NamingException ne){ throw new ServletException(ne); }catch(javax.xml.rpc.ServiceException se){ throw new ServletException(se); } } 部署說明文件: 一般都是通過JNDI查詢到相應(yīng)的Service接口,然后從Service接口中得到stub,最后調(diào)用web service的方法。部署文件中申明了名為"service/BookQuoteService"的Service接口,在代碼里獲取該接口的代碼是 jndiContext.lookup("java:comp/env/service/BookQuoteService"),前綴"java: comp/env/"是所有J2EE資源在JNDI樹種的parent Context。 在非J2EE環(huán)境中實現(xiàn)web service客戶端 在非J2EE環(huán)境中也可以實現(xiàn)web service客戶端,這時需要用到j(luò)avax.xml.rpc.ServiceFactory(或其子類,在axis中是 org.apache.axis.client.ServiceFactory)的靜態(tài)方法loadService得到service接口。接下來的調(diào)用代碼和J2EE中的類似。 動態(tài)代理調(diào)用 動態(tài)代理調(diào)用是Java web service的另一種方式。對于使用該方式的客戶端代碼,和生成stub的方式相比較,其變化不是很大。它和生成stub的方式主要區(qū)別在于前者在編譯時刻產(chǎn)生service接口和stub,后者則將這部分工作延遲到運行時刻。 動態(tài)代理調(diào)用的典型代碼和部署說明文件: package com.jwsbook.jaxrpc; import javax.naming.InitialContext; public class JaxRpcExample_2 { public static void main(String [] args) throws Exception{ String isbn = args[0]; InitialContext jndiContext = new InitialContext(); javax.xml.rpc.Service service = (javax.xml.rpc.Service) jndiContext.lookup("java:comp/env/service/Service"); BookQuote BookQuote_proxy = (BookQuote) service.getPort(BookQuote.class); float price = BookQuote_proxy.getBookPrice( isbn ); System.out.println("The price is = "+price); } } 由于不需要在編譯時刻產(chǎn)生service接口和stub,用JNDI lookup和部署說明時只使用了javax.xml.rpc.Service。得到service接口后通過getPort方法可以取得動態(tài)代理的 stub。getPort有兩種版本,getPort(java.lang.Class endpointInterface)和getPort(javax.xml.namespace.QName portName,java.lang.Class endpointInterface),通常當WSDL中一個PortType有一種以上的綁定時,如果需要得到某個綁定的port接口就使用后者,否者使用前者。QName是該綁定的完全限定名稱,有命名空間加上局部名構(gòu)成。對應(yīng)的QName對象的構(gòu)造方法有構(gòu)造函數(shù)法和靜態(tài)valueOf法,實例如下: // Use constructor method QName portName = new QName("http://www.Monson-Haefel/jwsbook/BookQuote", "BookQuoteLiteralPort"); // Use static valueOf() method String s = "{http://www.Monson-Haefel/jwsbook/BookQuote}BookQuoteLiteralPort"; QName qname2 = QName.valueOf(s); valueOf方法接受的String參數(shù)以"{namespace}localName"的模式構(gòu)成。 PortType有一種以上的綁定時還需要在JAX-RPC Mapping 文件中說明不指定QName版本的getPort方法對應(yīng)的port綁定。示例: <?xml version=‘1.0‘ encoding=‘UTF-8‘ ?> xmlns="http://java./xml/ns/j2ee" xmlns:mh="http://www.Monson-Haefel.com/jwsbook/BookQuote"...> ... ... 使用QName的動態(tài)代理調(diào)用實例: package com.jwsbook.jaxrpc; import javax.naming.InitialContext; import javax.xml.namespace.QName; public class JaxRpcExample_3 { public static void main(String [] args) throws Exception{ String isbn = args[0]; InitialContext jndiContext = new InitialContext(); javax.xml.rpc.Service service = (javax.xml.rpc.Service) jndiContext.lookup("java:comp/env/service/Service"); QName portName = new QName("http://www.Monson-Haefel/jwsbook/BookQuote", "BookQuoteLiteralPort"); BookQuote BookQuote_proxy = (BookQuote) service.getPort(portName, BookQuote.class); float price = BookQuote_proxy.getBookPrice( isbn ); System.out.println("The price is = "+price); } } 動態(tài)代理的底層實現(xiàn)是用java的反射機制和java.lang.reflect.Proxy完成的。 動態(tài)調(diào)用接口(DII) 動態(tài)調(diào)用接口的通常使用順序: 1. 獲得一個通用的service接口,比如通過JNDI lookup 2. 構(gòu)造代表WSDL中port和operation的QName對象,作為service接口的createCall方法的參數(shù),得到Call對象。 3. 準備operation所需的參數(shù),如果是原子類型則需要將其包裝成相應(yīng)的對象類型。視operation是否有返回值調(diào)用invoke或invokeOneWay方法。 4. 如果operation定義了INOUT,OUT參數(shù),則在invoke后調(diào)用getOutputValues,比如:java.util.List outputParams = call.getOutputValues(); 完整的代碼示例: package com.jwsbook.jaxrpc; import javax.naming.InitialContext; import javax.xml.rpc.Service; import javax.xml.rpc.Call; import javax.xml.namespace.QName; public class JaxRpcExample_4 { public static void main(String [] args) throws Exception{ String isbn = args[0]; InitialContext jndiContext = new InitialContext(); javax.xml.rpc.Service service = (javax.xml.rpc.Service) jndiContext.lookup("java:comp/env/service/Service"); QName portName = new QName("http://www.Monson-Haefel.com/jwsbook/BookQuote", "BookQuotePort"); QName operationName = new QName("http://www.Monson-Haefel.com/jwsbook/BookQuote", "getBookPrice"); Call call = service.createCall(portName,operationName); Object [] inputParams = new Object[]{isbn}; Float price = (Float)call.invoke(inputParams); System.out.println("The price is = "+price.floatValue()); } } |
|
|