程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 在WEBLOGIC SERVER 10中使用JAX-WS和JAXB

在WEBLOGIC SERVER 10中使用JAX-WS和JAXB

編輯:關於JAVA

JAX-WS(Java Architecture for Web Services)是JAX-RPC的後續版本。它是一種基於標准的API,可用於編寫、匯編和部署Java Web services。JAXB(Java Architecture for XML Binding)是一種Java/XML綁定技術。JAX-WS將使用JAXB處理所有的Java綁定操作。

本文將簡要介紹BEA WebLogic Server 10.1中所支持的JAX-WS 2.0和JAXB 2.0。讀者可通過文章中的示例代碼入門。

JAXB 2.0 Java開發人員快速指南

JAX-WS使用JAXB處理所有的Java綁定操作,因此本文將重點討論與JAX-WS有關的JAXB。熟練的Java開發人員通常都很繁忙。考慮到這一點,我將主要討論以下兩方面內容:

目前使用JAXB 2.0可以完成的任務。

目前使用JAXB 2.0無法完成的任務。

如果您忙得連閱讀這篇文章的時間都沒有,請直接 下載 本文所提供的示例代碼。壓縮包中的README文件介紹了具體的操作步驟。

使用JAXB 2.0可以完成那些任務?

下面列出了使用JAXB 2.0可以實現的一些比較有趣的任務。我的意思並不是說使用其他Java-to-XML/XML-to-Java綁定技術就不能實現這些操作。我只是列出了使用JAXB 2.0可以完成的操作:

通過含有一個或多個<xs:schema>元素的WSDL生成Java對象圖。這些<xs:schema>元素可以使用<xs:import>和<xs:include>元素引用其他的<xs:schema>元素。

通過Java對象圖生成XML Schema文檔。

利用快速信息集分析程序(SAX和StAX)和串行器(serializer)。

隨機訪問XML文檔的XML信息集。

直接在XML Schema文件或外部綁定自定義文件中嵌入綁定聲明。

在取消編組(unmarshalling)時使用基於事件的流模型。

編組二進制數據(比如說,處理MTOM和MIME附件)。

開發自己的插件,擴展JAXB代碼生成功能。然後,這些插件(作為類封裝在一個.jar文件中)可以訪問JAXB生成的代碼,還可生成另外的類/方法/字段/注釋/評論。

編寫定制代碼將已有類轉化為由JAXB模式編譯程序生成的類。

使用JAXB 2.0無法完成的操作

下面列出了使用JAXB 2.0無法完成的操作(或者說是我不知道如何實現):

通過XML文檔生成XML模式。實際上,這並沒有什麼大不了的。因為其他工具(如Stylus Studio、XMLSpy和XMLBuddy Pro)可以實現這一功能。

匹配StAX或SAX解析的性能指數。解析同一XML文檔時,SAX需要10ms,StAX需要46ms,而JAXB 2.0需要59ms。

使用JAXB進行Java綁定的示例POJO JAX-WS Web服務

JAX-WS是一種基於標准的API,可用於編寫、匯編和部署Java Web services。它使用JAXB處理所有與此相關的Java綁定操作。JAX-WS 2.0/2.1並不支持JAX-RPC或Apache Beehive XMLBean類型的使用,只支持JAXB類型的XMLBean。

JAX-WS提供了兩個編程模型,用於開發Web服務端點。

1.從Java開始(Start from Java)——此編程模型使您能夠充分地控制Web服務端的方法簽名(method signature)中所使用的Java數據類型。在該模型中,您可以手動編寫(或者使用工具生成)Java對象,這些Java對象將作為Web服務操作及JWS注釋的輸入參數和返回值使用。

BEA為“從Java開始”編程模型提供了jwsc Ant任務。它將Glassfish wsimport Ant任務封裝在內部(即從內部調用)。因此我們不用直接在build.xml文件中使用Ant任務。

Ant Task Reference for jwsc 這篇BEA文檔介紹了如何使用<jws>元素的type="JAXWS"屬性生成JAXB工件。jwsc Ant任務中的<binding>子元素可用於指定所要使用的JAXB綁定自定義文件。

2.從WSDL開始(Start from WSDL)——此編程框架將通過WSDL的內容生成Web服務端點的主干代碼。WSDL中<xs:schema>部分生成的Java數據類型將作為Web服務操作的輸入參數和返回值使用。

BEA為“從WSDL開始”編程模型提供了wsdlc Ant任務。它將Glassfish wsimport Ant任務封裝在內部。因此我們不用直接在build.xml文件中使用Ant任務。

Ant Task Reference for wsdlc 這篇BEA文檔介紹了如何使用<wsdlc>元素的type="JAXWS"屬性生成JAXB工件。wsdlc Ant任務中的<binding>子元素可用於指定所要使用的JAXB綁定自定義文件。

文章的其余部分將介紹如何創建、部署和測試基於POJO(Plain-Old Java Object)的JAX-WS Web服務端點,即DataStagingService。

創建定制文件

第一步需要創建一個JAX-WS定制文件。該文件還可以充當JAXB綁定定制文件,並允許我們控制JAX-WS和JAXB構建時流程,以及它們生成的工件。

定制文件是一個XML文檔,它符合XML模式的http://java.sun.com/xml/ns/jaxws和http://java.sun.com/xml/ns/jaxb名稱空間。有關創建該定制文件的詳細信息,請參閱 JAX-WS 2.0 Beta Customizations。

DataStagingService Web服務的JAX-WS定制文件相當小,因此我列出了該文件的內容:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bindings
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns="http://java.sun.com/xml/ns/jaxws"
wsdlLocation="DataStagingService2.wsdl"
>
<bindings
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
node="wsdl:definitions"
>
<package name="services.datastaging">
<jxb:javadoc>
<![CDATA[<body>Package level documentation for generated
package services.datastaging.</body>]]>
</jxb:javadoc>
</package>
<jxb:schemaBindings>
<jxb:package name="com.acmeworld.irad.services.datastaging"/>
</jxb:schemaBindings>
</bindings>
</bindings>

我將主要使用該定制文件控制生成類的Java包名。您可以在該定制文件中實現更多其他功能,請參閱 JAX-WS 2.0 Beta Customizations。

下面的清單展示了DataStagingService Web服務的WSDL中所使用的XML Schema:

<xs:schema
targetNamespace="http://services.irad.acmeworld.com/datastaging"
xmlns:tns="http://services.irad.acmeworld.com/datastaging"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
>
<xs:complexType name="DataStaging">
<xs:sequence>
<xs:element name="inputURIs">
<xs:complexType>
<xs:sequence>
<xs:element name="inputURI" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="uri" type="xs:anyURI"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="DataStagingResponse">
<xs:sequence>
<xs:element name="outputURIs">
<xs:complexType>
<xs:sequence>
<xs:element name="outputURI" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="uri" type="xs:anyURI"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:element name="dataStaging" type="tns:DataStaging"/>
<xs:element name="dataStagingResponse" type="tns:DataStagingResponse"/>
</xs:schema>

此WSDL的XML Schema部分中的內容相當普通。請求和響應消息是由普通的(具有匿名和顯式內容模型的)全局complexType元素一起創建的。DataStagingService是一個doc/literal樣式的Web服務,因此其中含有全局元素與WSDL的<part>元素結合使用。

使用build.xml文件構建

我將使用WebLogic Server 10中附帶的Eclipse IDE繼續演示。WebLogic for Workshop 10中並沒有特定的Eclipse IDE插件可用於JAX-WS和JAXB開發,因此我將使用build.xml Ant腳本和Ant View窗口。

這個build.xml文件的內容太長,因此我只列出了其中的重要部分。

<path id="jaxws.classpath">
<fileset dir="${bea.home}/modules">
<include name="javax.xml.stream_1.0.0.0.jar"/>
<include name="javax.jws_2.0.jar"/>
<include name="javax.xml.bind_2.0.jar"/>
<include name="javax.xml.ws_2.0.jar"/>
<include name="javax.xml.soap_1.3.0.0.jar"/>
<include name="javax.activation_1.1.jar"/>
<include name="glassfish.jaxws.rt_2.0.1.jar"/>
<include name="glassfish.jaxb_2.0.5.jar"/>
<include name="glassfish.jaxws.saaj.impl_2.0.1.jar"/>
<include name="glassfish.jaxws.tools_2.0.1.jar"/>
</fileset>
</path>

上面的清單指出了build.xml文件中所使用的<path>元素。它表示WebLogic Server 10將在其JAX-WS和JAXB實現中使用共享的Java EE庫模塊來實現類。如您所見,這些類來自Glassfish RI JAR,而並非由WebLogic Server 10 Web Services棧開發小組編寫。共享的Java EE庫模塊有利於Glassfish JAR的封裝,並允許將它們的單個副本用於各種內部(對於BEA)或外部用途。眾所周知,這些庫模塊位於${BEA_HOME}/modules目錄。

上述清單中的JAR位於用戶定義的庫中。這樣更易於編寫在Eclipse IDE內部使用JAX-WS和JAXB API的代碼。

生成JAX-WS服務端點和JAXB類

接下來,我們將實現DataStagingService Web服務的代碼。首先,運行BEA wsdlc Ant任務,目的是生成主干JAX-WS端點實現和JAXB類。

WebLogic Server 10.1將使用Glassfish Project項目中的jar文件用於其JAX-WS和JAXB實現。type="JAXWS"屬性將指定使用JAX-WS和JAXB,而不是JAX-RPC。

<target name="run-wsdlc" depends="clean">
<taskdef name="wsdlc" classname="weblogic.wsee.tools.anttasks.WsdlcTask"
classpathref="compile.classpath" />
<property name="client.binding" value="custom-client.xjb"/>
<wsdlc type="JAXWS"
srcWsdl="etc/${wsdl.file.name}.wsdl"
destJwsDir="WebContent/WEB-INF/lib"
destImplDir="${src.dir}"
explode="false"
verbose="${verbose}"
debug="${debug}"
failonerror="true">
<binding dir="etc" includes="${client.binding}"/>
<classpath>
<path refid="compile.classpath"/>
</classpath>
</wsdlc>
/target>

type="JAXWS"屬性和<binding>子元素需要格外注意。

這時,我們應該能夠運行Ant構建文件了。結果將生成JAX-WS端點實現的代碼。由於我提供了一個定制文件,因此生成代碼將位於com.acmeworld.irad.services.datastaging包中。JAX-WS端點實現的完整代碼比較長,因此我只摘錄了其中的一部分:

public com.acmeworld.irad.services.datastaging.DataStagingResponse.OutputURIs dataStaging(com.acmeworld.irad.services.datastaging.DataStaging.InputURIs inputURIs)
{
DataStagingResponse dataStagingResponse = null;
InputStream inputstream = null;
try
{
//DataStaging.InputURIs contains zero or more
//DataStaging.InputURIs.InputURI JAXB objects.
//We loop through them, and use one of their getter
//methods to print out a bound value.
DataStaging.InputURIs.InputURI inputURI = null;
List inputURIList = inputURIs.getInputURI();
for (int i = 0; i < inputURIList.size(); i++)
{
inputURI = inputURIList.get(i);
log("dataStaging(InputURIs)", "inputURI.getUri()=" + inputURI.getUri());
}
//Next, we show one way to use the JAXB API, to convert
//the DataStaging.InputURIs input parameter to a byte[].
//This byte[] will contain an XML representation of that
//input parameter.
JAXBContext jc = JAXBContext.newInstance(DataStaging.InputURIs.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
JAXBElement je = new JAXBElement(
new QName("http://services.irad.acmeworld.com/datastaging","inputURIs"),
DataStaging.InputURIs.class,
inputURIs
);
marshaller.marshal(je, baos);
//We use an existing XML file for the response from the
//Web service operation. We’ll load this XML file from
//the WEB-INF/classes directory, and use the JAXB API
//to create the JAXB object of our response.
inputstream = Thread.currentThread().getContextClassLoader().getResourceAsStream("SampleDataStagingResponseDocument.xml");
jc = JAXBContext.newInstance(DataStagingResponse.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
dataStagingResponse = (DataStagingResponse)unmarshaller.unmarshal(inputstream);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
finally
{
if (inputstream != null) try {} catch (Exception e){}
}
return dataStagingResponse.getOutputURIs();
}

其中的代碼注釋很好地解釋了其過程,因此我在此處就不再贅述了。

編譯JAX-WS服務端點

BEA jwsc Ant任務用於編譯JAX-WS服務端點並生成待部署的WAR文件。

<target name="run-jwsc">
<taskdef name="jwsc" classname="weblogic.wsee.tools.anttasks.JwscTask"
classpathref="compile.classpath" />
<jwsc
destdir="${domain.home}/deployments/${project.name}"
srcdir="${src.dir}/${package.path}"
classpath="WebContent/WEB-INF/lib/${wsdl.file.name}_wsdl.jar"
keepGenerated="${keep}"
>
<binding dir="etc" includes="${client.binding}"/>
<module explode="false" name="${portType.name}Impl">
<jws
type="JAXWS"
file="${service.name}Impl.java"
compiledWsdl="WebContent/WEB-INF/lib/${wsdl.file.name}_wsdl.jar"
>
<WLHttpTransport
contextPath="datastaging"
serviceUri="DataStagingService"
portName="DataStagingServicePort"
/>
</jws>
</module>
<classpath>
<path refid="compile.classpath"/>
<pathelement location="WebContent/WEB-INF/lib/${wsdl.file.name}_wsdl.jar"/>
</classpath>
</jwsc>
</target>

同樣,此處的type="JAXWS"屬性和<binding>子元素值得格外注意。該代碼還演示了如何避免將特定於WebLogic注釋(比如說@WLHttpTransport)放在JWS中。

使用build.xml文件部署

JAX-WS中有一個倍愛好評的特性,即部署描述符的使用是可選的。這種特性很好,因為它解決了多個供應商所提供的JAX-WS實現之間的可移植性問題。

基於POJO的JAX-WS Web services已封裝為Java EE Web應用程序,並且WebLogic Server 10所提供的wsdeploy Ant任務可以將這些應用程序部署到運行中的WLS實例上。此處,我將在build.xml文件中使用該wsdeploy Ant任務。

<target name="deploy">
<property name="wls.username" value="weblogic"/>
<property name="wls.password" value="weblogic"/>
<property name="wls.hostname" value="localhost"/>
<property name="wls.port" value="7031"/>
<property name="wls.server.name" value="W4WPAdminServer"/>
<taskdef name="wldeploy"
classname="weblogic.ant.taskdefs.management.WLDeploy"
classpathref="compile.classpath" />
<wldeploy
action="deploy"
name="${project.name}"
source="${domain.home}/deployments/${project.name}"
user="${wls.username}"
password="${wls.password}"
verbose="true"
adminurl="t3://${wls.hostname}:${wls.port}"
targets="${wls.server.name}"
/>
</target>

使用WebLogic Test Client進行測試

WebLogic Test Client是一個Java EE Web應用程序。和WebLogic Server Administration Console (console.war)一樣,它自動部署於您的WebLogic Server 10.1實例中。該應用程序的URL為:

http://<host>:<port>/wls_utc

DataStagingService的WSDL的URL為:

http://<host>:<port>/datastaging/DataStagingService?WSDL

輸入該WSDL URL之後,單擊“Test”按鈕,然後便可在接下來出現的頁面中輸入測試請求XML。下面是一個示例請求XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<dataStaging xmlns="http://services.irad.acmeworld.com/datastaging">
<inputURIs>
<inputURI>
<uri>http://www.altova.com</uri>
</inputURI>
<inputURI>
<uri>http://www.amazon.com</uri>
</inputURI>
</inputURIs>
</dataStaging>

WebLogic Test Client相當優秀,但是它實際上並不能測試在客戶端上使用JAXB和JAX-WS。最後一步將實現這一任務。

使用JAX-WS Web服務客戶端進行測試

最後,我們將使用JAX-WS Web服務客戶端調用DataStagingService Web服務。最後一部分的代碼要比JAX-WS服務端點的代碼稍微復雜一些,因此它需要使用JAXB API。

try
{
DataStagingService service = new DataStagingService(
new URL("http://localhost:7031/datastaging/DataStagingService?WSDL"),
new QName("http://services.irad.acmeworld.com/datastaging",
_properties.getProperty("datastaging.service.portName"))
);
Dispatch sourceDispatch = service.createDispatch(
new QName("http://services.irad.acmeworld.com/datastaging",
"DataStagingService"),
Source.class,
Service.Mode.PAYLOAD
);
InputStream inputstream = Thread.currentThread().getContextClassLoader().
getResourceAsStream("SampleDataStagingRequestDocument.xml");
Source responseSource = sourceDispatch.invoke(new StreamSource(inputstream));
javax.xml.transform.TransformerFactory factory =
javax.xml.transform.TransformerFactory.newInstance();
javax.xml.transform.Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(javax.xml.transform.OutputKeys.METHOD, "xml");
javax.xml.transform.stream.StreamResult streamResult =
new javax.xml.transform.stream.StreamResult();
streamResult.setOutputStream(new java.io.ByteArrayOutputStream());
transformer.transform(responseSource, streamResult);
System.out.println((new StringBuffer()).append("response=").
append(streamResult.getOutputStream()).toString());
}
catch(Throwable throwable)
{
throwable.printStackTrace();
System.out.println((new StringBuffer()).append("Unexpected exception: ").
append(throwable.getMessage()).toString());
}

其中大多數代碼專門用於執行XSL轉換,並且使用了JDK中的JAXP API類。首先,創建一個DataStagingService服務樁(stub)。該服務樁將接收一個URL對象(指向服務端點的WSDL)和一些與XML相關的內容,用於建立要調用的服務。後者將在檢索WSDL之後使用。

注意,DataStagingService服務樁和相關類是由BEA clientgen Ant任務生成的。我並沒展示這些代碼,不過該Ant任務也擁有一個type="JAXWS"和一個<binding>子元素。

摘錄代碼的其余部分包括:

創建Dispatch對象,該對象用於調用Web服務操作。Dispatch對象在功能上等同於JAX-RPC中的Call對象(與DII編程模型一起使用)。

通過XML文檔創建有效負載。這違背了“為各個元素實例化一個對象”的實踐,JAX-RPC需要這樣。

調用Web服務操作。此外需要格外小心,因為“操作名稱”包裝器元素並不會自動添加。如果服務端點需要一個,則需要自己添加。

使用JAXP轉換類將響應從Web服務操作編組到java.io.ByteArrayOutputStream中。您可以處理所需的一切內容(比如說byte[]、String和XML)。同樣,這遠沒有在JAX-RPC中處理JavaBean圖(或javax.xml.soap.SOAPElement對象)費力。

以上是整個步驟的總結。希望您可更好的理解如何在WebLogic Server 10中使用JAX-WS 2.0和JAXB 2.0實現。這些實現中的API即可以在服務提供者端使用,也可以在服務用戶端使用。請查看我所提供的示例代碼,您會發現其中沒有使用(或導入)任何特定於WebLogic的類。這表示該代碼是完全可移植的,並且應該能夠在Axis2上編譯,而無需對代碼(或定制文件)進行任何修改。但是,您需要修改build.xml文件,使JAX-WS和JAXB實現使用Axis2所使用的.jar文件。還需要修改用於JAX-WS、JAXB和部署的Ant任務。

一些最佳實踐

以下列出了在WebLogic Server 10中使用JAX-WS和JAXB 實現的一些最佳實踐:

避免在代碼中使用特定於供應商的注釋。這樣在嘗試不同供應商的JAX-WS實現時就無需對代碼進行修改。通常,JAX-WS實現供應商都提供了在Ant任務中訪問特定於供應商注釋的方法。WebLogic Server使用的是這一選項,因此您應該利用這一特性,以避免在JWS中使用特定於供應商的注釋。

在可能的地方使用JAXP StreamSource和 and StreamResult。javax.xml.transform.stream.StreamSource和javax.xml.transform.stream.StreamResult所類提供的方法可以最有效地處理Java串行化(和並行化)問題。因此,您應該盡可能地使用它們。

緩存JAXBContext對象。javax.xml.bind.JAXBContext對象是一個用於通過Java類創建JAXB對象的工廠。創建JAXBContext對象需要的開銷比較大,因此應該緩存它們從而便於重用。

使用JAXBElement編組內部類。JAXB 2.0將使用內部類用於匿名complexType元素。如果您之後在Web服務操作的方法簽名中使用其中某個元素,那麼將在構建時接收到一個javax.xml.bind.MarshalException異常。問題是內部類並不是高級元素,因此並沒有@XmlRootElement注釋。解決的方法是為內部類創建一個JAXBElement對象。要了解如何創建該對象,請在DataStagingServiceImpl.java文件中搜索"JAXBElement"。

下載

wls10wss_jaxws-article1.zip——該zip文件含有本教程所使用的所有源代碼。

結束語

JAX-WS和JAXB是用於構建下一代基於Java的Web服務的最有前途的兩個API。如今,WebLogic Server 10 Web Services棧通過Glassfish JAR和BEA Ant任務這兩個API都提供了支持。

您可以使用WebLogic Server 10 Web Services棧為任何JAX-WS實現編寫、構建和部署JAX-WS Web服務,而不僅限於WebLogic Server 10中的實現。Jwsc和wsdlc Ant任務已經經過修改,現在可允許您指定生成JAX-WS和JAXB工件時所使用的定制文件。可以使用<binding>子元素實現這一目的。Jwsc和wsdlc Ant任務將從內部調用Sun的wsimport Ant任務。

希望您可以通過本文了解使用WebLogic Server 10 Web Services棧生成JAX-WS和JAXB工件是多麼地容易。但是,創建定制文件卻並非易事。我們可以通過定制文件影響工件的生成流程。不過也不用擔心,我將在後續的幾篇文章中介紹如何創建定制文件。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved