本文根據(jù) SUN 官方網(wǎng)站 Enterprise Java Technologies Tech Tips 欄目上的一篇文章改寫(xiě)的,所有過(guò)程均調(diào)試通過(guò)。
一.前言
SOA 思想的核心在于 "S" ,凡是從服務(wù)的角度去看待系統(tǒng)功能,并且構(gòu)建和實(shí)現(xiàn)應(yīng)用,都可以認(rèn)為是 SOA 的某種實(shí)現(xiàn)形式。下面一段要說(shuō)的是: SOA 技術(shù)的核心在于 "O" --只有做到 Service-Orientation 的技術(shù),才能真正稱為 SOA 技術(shù)。
怎樣才能算作 Service-Orientation ?我們?cè)僖? OO 進(jìn)行類(lèi)比: VB 之所以被稱為基于對(duì)象 (Object-Based) 而不是面向?qū)ο? (Object-Oriented) 的語(yǔ)言,是因?yàn)? VB 的運(yùn)行時(shí)結(jié)構(gòu)不具有 VMT 等基本構(gòu)造,語(yǔ)法上也不支持私有成員,繼承等基礎(chǔ)特性,兩者結(jié)合,就造成無(wú)法支持封裝,繼承,多態(tài)等面向?qū)ο蟮年P(guān)鍵技術(shù)。一句話, VB 不是圍繞 “ 對(duì)象 ” 這個(gè)核心概念設(shè)計(jì)的語(yǔ)言。 對(duì)于 SOA 技術(shù),它也可以從這個(gè)角度劃分兩個(gè)層次:一個(gè)是 SOA 的 “ 運(yùn)行時(shí) ” 相關(guān)結(jié)構(gòu)標(biāo)準(zhǔn),例如 SOAP , WSDL,WS-* 等,相當(dāng)于 OO 中的對(duì)象內(nèi)部結(jié)構(gòu), VMT 構(gòu)造等。另外一個(gè)則是語(yǔ)言和工具層面的支持,例如基于元數(shù)據(jù)的服務(wù)描述,支持 Web Service 的類(lèi)庫(kù), Proxy 生成工具等,相當(dāng)于 OO 語(yǔ)言中提供的基本 OO 語(yǔ)法,類(lèi)庫(kù),編繹器等。這兩個(gè)層次共同構(gòu)成 SOA 體系結(jié)構(gòu)中的要素,讓人們能夠圍繞 “ 服務(wù) ” 這個(gè)核心概念進(jìn)行系統(tǒng)開(kāi)發(fā)和應(yīng)用。因此,一種技術(shù)架構(gòu),平臺(tái)或產(chǎn)品要稱作 SOA ,應(yīng)當(dāng)同時(shí)具備這一兩方面的特征。
所以,下面將要討論的 JAX-WS 技術(shù),從上面的觀點(diǎn)來(lái)看,也就是 SOA 技術(shù)的第二個(gè)層次,即語(yǔ)言和工具層面的支持 --Java ,例如基于元數(shù)據(jù)的服務(wù)描述,支持 Web Service 的類(lèi)庫(kù), Proxy 生成工具等 .
Java API for XML Web Services ( JAX-WS ) 2.0, 是 Java EE 5 平臺(tái)的一個(gè)重要的部分。作為 Java API for XML-baseed RPC 1.1 ( JAX-RPC )的后續(xù)版本,在 JAX-RPC 1.1 中 , 開(kāi)發(fā)人員需要寫(xiě)一個(gè)接口類(lèi) Service Endpoint Interface(SEI), 在 JAX-WS 2.0 中 , 開(kāi)發(fā)人員一上來(lái)就可以直接寫(xiě)自己的實(shí)現(xiàn)類(lèi) . 通過(guò)使用 annotations, 自動(dòng)生成 SEI 和其他一些文件 . 這樣有助于開(kāi)發(fā)人員專注于自己想開(kāi)發(fā)的部分 , 而不必要地分散精力去維護(hù)其他的一些附屬文件 .
二 . 快速實(shí)踐 JAX-WS2.0
下面通過(guò)一個(gè)兩個(gè)數(shù)相加的簡(jiǎn)單例子來(lái)看看 ,JAX-WS 2.0 API 的應(yīng)用過(guò)程 . 程序是一個(gè)獨(dú)立的客戶端傳給服務(wù)端兩個(gè)整數(shù) , 經(jīng)過(guò)服務(wù)端處理后 , 將結(jié)果返回到客戶端并打印出來(lái) .
一 . 環(huán)境配置 .
1. JDK 5.0 or higher
下載 : http://java.sun.com/javase/downloads/index.jsp
2. Java EE 5.0 App Server.
這個(gè)例子是基于 Java EE 5 的一個(gè)開(kāi)源實(shí)現(xiàn)項(xiàng)目 GlassFish 。 https://glassfish.dev.java.net/public/downloadsindex.html
本例子所需的基本代碼的壓縮包可以通過(guò)這個(gè) 鏈接 下載。里面包括了這個(gè)例子需要的代碼,構(gòu)建腳本和一個(gè) build 文件。
環(huán)境變量的配置:
·
GLASSFISH_HOME.
這個(gè)應(yīng)該指向你安裝
GlassFish
的目錄
(
比如,我系統(tǒng)上的是:
J:/Sun/AppServer)
·
ANT_HOME.
這個(gè)應(yīng)該指向
ant
所安裝的目錄。在你下載
GlassFish bundle
時(shí)
Ant
已經(jīng)被包含在里面了。
(
對(duì)于
Windows
系統(tǒng),它是在
lib/ant
子目錄
)
。不過(guò)你也可以從
Apache Ant Project page.
下載
Ant
。對(duì)于這個(gè)例子需要
Apache ant 1.6.5
·
JAVA_HOME.
這個(gè)應(yīng)該指向你系統(tǒng)上安裝的
JDK 5.0
(
or higher
)的目錄。
同時(shí),把
ant
的
bin
目錄添加到
Path
環(huán)境變量中去
(J:/apache-ant-1.6.5/bin)
,當(dāng)然了
JDK
的
bin
目錄也加進(jìn)去了。
然后
下載例子的代碼包
并且解壓。根文件夾是
jaxws-techtip
。
endpoint/
目錄下有一個(gè)文件
Calculator.java
client/
目錄下有一個(gè)文件
JAXWSClient.java
二
.
編寫(xiě)構(gòu)建服務(wù)端
隨著第一步環(huán)境配置的完全,現(xiàn)在該開(kāi)始構(gòu)建一個(gè) web 服務(wù)了。在這個(gè)例子里, web 服務(wù)是從一個(gè) Java 類(lèi)來(lái)開(kāi)發(fā)的。為了構(gòu)建這個(gè) web 服務(wù):
1 . 寫(xiě)一個(gè)端點(diǎn)實(shí)現(xiàn)類(lèi) ( endpoint implementation class) 。
2 . 編繹這個(gè) 端點(diǎn)實(shí)現(xiàn)類(lèi)。
3 . 有選擇的產(chǎn)生對(duì) web 服務(wù)的運(yùn)行必須具備的那些可移植的制品。
4 . 把 web 服務(wù)打包成一個(gè) WAR 文件并且在 App Server 中部署它。
1 編寫(xiě)實(shí)現(xiàn)類(lèi) .
進(jìn)到
endpoint/
目錄下,可以看到里面有一個(gè)文件
Calculator.java.
它是一個(gè)端點(diǎn)實(shí)現(xiàn)類(lèi),具備有對(duì)兩個(gè)整數(shù)進(jìn)行相加的簡(jiǎn)單服務(wù)。
JAX-WS 2.0
大量地依賴注釋(
annotations
)的使用,它是
A Metadata Facility for the Java Programming Language (JSR 175)
描述的規(guī)范和
Web Services Metadata for the Java Platform (JSR 181)
描述的規(guī)范。






















研究上面的實(shí)現(xiàn)類(lèi)
Calculator
,注意到類(lèi)里的兩個(gè)注釋的使用
@WebService
跟
@WebMethod
。一個(gè)正確的端點(diǎn)實(shí)現(xiàn)類(lèi)必須包含有一個(gè)
@WebService
注釋。這個(gè)注釋標(biāo)注這個(gè)類(lèi)將作為一個(gè)
web
服務(wù)對(duì)外開(kāi)放。
@WebService
的
name
屬性表明了
web
服務(wù)描述語(yǔ)言
(WSDL)
里的端口類(lèi)型
(
portType
)
(在這個(gè)例子里是
”Calculator”
)。而
serviceName="CalculatorService"
對(duì)應(yīng)的是一個(gè)
WSDL
里的服務(wù)元素
(service)
。
targetNamespace
屬性為
WSDL
說(shuō)明了
XML
的命名空間。所有的這些屬性都是可選的。對(duì)于這些屬性的默認(rèn)值是什么,請(qǐng)參考
Web Services Metadata for the Java Platform
規(guī)范,
JSR 181
。
再來(lái)看看另外一個(gè)重要的注釋
@WebMethod
,被它注釋過(guò)的方法說(shuō)明將它以一個(gè)
web
服務(wù)的方法暴露出來(lái),被其他應(yīng)用來(lái)調(diào)用。
@WebMethod
注釋里的
operationName
聲明了
WSDL
里的一個(gè)元素
WSDL
operation
(在這個(gè)例子里,
”add”
)
,
另外一
個(gè)屬性
action =("
urn:Add
"),
它為
WSDL
還有一些從這個(gè)
web
服務(wù)操作
(web service operation)
生
成的元素聲明了一個(gè)命名空間。這兩個(gè)屬性都是可選的。如果你沒(méi)有列出來(lái)的
話, WSDL 操作 (operation) 的值將會(huì)默認(rèn)為方法名,還有 action 值也會(huì)默認(rèn)為
服務(wù)的
targetNamespace
。
2
編繹實(shí)現(xiàn)類(lèi)
寫(xiě)完了上面的實(shí)現(xiàn)類(lèi)之后,你需要編繹它。點(diǎn)擊
開(kāi)始-
>
程序-
>Sun Microsystems
-
>“Start Default Server”
啟動(dòng)應(yīng)用服務(wù)器或者通過(guò)在
DOS
窗口下敲下面的命令來(lái)啟動(dòng)它:
<GF_install_dir>/bin/asadmin start-domain domain1
,其中
GF_install_dir
是你安裝
GlassFish
的目錄,也就是說(shuō)先到
<GF_install_dir>/bin
目錄下,然后用命令
asadmin start-domain domain1
來(lái)啟動(dòng)應(yīng)用服務(wù)器。現(xiàn)在將目錄轉(zhuǎn)到
jaxws-techtip
文件夾下,運(yùn)行下面的
ant
命令,也就是執(zhí)行第一個(gè)任務(wù)
complie:
ant compile
執(zhí)行這個(gè)命令就相當(dāng)于執(zhí)行以下的 javac 命令 ( 都是在同一行 ) :
javac -classpath $GLASSFISH_HOME/lib/javaee.jar -d
./build/classes/service/ endpoint/Calculator.java
3 為 web 服務(wù)的執(zhí)行產(chǎn)生可移植的制品
這一步是可選的。如果在這個(gè) web 服務(wù)的部署期間,他們沒(méi)有和一個(gè)可配置的服務(wù)單元綁定, GlassFish 的部署工具能夠自動(dòng)地產(chǎn)生這些制品。然而對(duì)于剛剛接觸 JAX-WS 來(lái)說(shuō),對(duì)于弄清楚整個(gè)編程模式來(lái)說(shuō),通過(guò)手動(dòng)產(chǎn)生地會(huì)話會(huì)更有幫助,即運(yùn)行下面的命令:
ant generate-runtime-artifacts
這個(gè)任務(wù)將會(huì)在 jaxws-techtip 目錄下生成 build/generated 目錄,并且運(yùn)行了下面的 wsgen 命令 ( 都是在同一行 ):
$GLASSFISH_HOME/bin/wsgen -cp ./build/classes/service -keep -d ./build/classes/service –r ./build/generated -wsdl endpoint.Calculator
一個(gè) WSDL 文件 (CalculatorService.wsdl) 在 build/generated 目錄下生成了,還在同個(gè)目錄下生成了另外一個(gè) schema 文件 (CalculatorService_schema1.xsd), 它為 CalculatorService.wsdl 定義了 schema 。
JavaBean 技術(shù)組件 ( JavaBeans ) 在編組 ( marshaling,java->XML ) 的方法調(diào)用,響應(yīng),還有 service-specific 異常 中起了很大的作用。這些類(lèi)將會(huì)在 web 服務(wù)在一個(gè)應(yīng)用服務(wù)器中運(yùn)行的時(shí)候被使用。 JavaBean 類(lèi)在 jaxws-techtip 目錄下的 /build/classes/service/endpoint/jaxws 目錄被生成了,這些類(lèi)是:
Add.java
Add.class
AddResponse.java
AddResponse.class
4 打包并部署 WAR 文件
接下來(lái)你需要做的工作就是對(duì)服務(wù)進(jìn)行打包和部署。為了做這個(gè),你需要在一個(gè)部署描述符中詳細(xì)說(shuō)明這個(gè)服務(wù)。 Web 服務(wù)可以綁定成 servlet 的形式或者無(wú)狀態(tài)的 session bean 形式打包成 Web Archive (WAR) 文件。在這個(gè)例子里把它綁定為一個(gè) servlet 。
為了把這個(gè)服務(wù)打包成一個(gè) WAR 文件,定位到 jaxws-techtip 文件夾,并且在 DOS 窗口上運(yùn)行下面的命令:
ant pkg-war
對(duì)于這個(gè) war 文件的結(jié)構(gòu),我們可以到 build.xml 文件里看看 pkg-war 目標(biāo):
<
target
name
="pkg-war"
depends
="init-common">
<
mkdir
dir
="${assemble.dir}"/>
<
echo
message
="mybuildclassesdiris:${build.classes.dir}"
level
="verbose"/>
<
mkdir
dir
="${build.classes.dir}/tmp"/>
<
mkdir
dir
="${build.classes.dir}/tmp/WEB-INF"/>
<
mkdir
dir
="${build.classes.dir}/tmp/WEB-INF/classes"/>
<
mkdir
dir
="${build.classes.dir}/tmp/WEB-INF/wsdl"/>
<
copy
file
="${web.xml}"
tofile
="${build.classes.dir}/tmp/WEB-INF/web.xml"
failonerror
="false"/>
<
copy
todir
="${build.classes.dir}/tmp/WEB-INF/classes">
<
fileset
dir
="${build.classes.dir}/service">
<
include
name
="**/*.class"/>
<
include
name
="**/${handler.name}"/>
</
fileset
>
</
copy
>
<
copy
todir
="${build.classes.dir}/tmp/WEB-INF/wsdl">
<
fileset
dir
="${build.generated.dir}">
<
include
name
="**/*.*"/>
</
fileset
>
</
copy
>
<
echo
message
="Creatingwarfile${assemble.dir}/${appname}-web.war"
level
="verbose"/>
<
jar
jarfile
="${assemble.dir}/${appname}-web.war"
update
="true">
<
fileset
dir
="${build.classes.dir}/tmp"
casesensitive
="yes">
<
include
name
="**/*class*"/>
<
include
name
="**/${handler.name}"/>
</
fileset
>
<
fileset
dir
="${build.classes.dir}/tmp/"
casesensitive
="true">
<
include
name
="WEB-INF/web.xml"/>
</
fileset
>
<
fileset
dir
="${build.classes.dir}/tmp"
casesensitive
="yes">
<
include
name
="WEB-INF/wsdl/*.*"/>
</
fileset
>
</
jar
>
<
echo
message
="createdwarfile${assemble.dir}/${appname}-web.war"
level
="verbose"/>
</
target
>
我們可以通過(guò)執(zhí)行下面的命令來(lái)部署已經(jīng)生成的 war 文件:
ant deploy-app
這等同于執(zhí)行下面的 asadmin 部署命令 ( 都是在同一行 ) :
bash$GLASSFISH_HOME/bin/asadmin deploy --user admin
--passwordfile passwd --host localhost --port 4848
--contextroot jaxws-webservice --upload=true --target server
三 編寫(xiě)構(gòu)建客戶端
在你部署完這個(gè) web 服務(wù)之后,你可以通過(guò)一個(gè)客戶端程序來(lái)訪問(wèn)它。下面是構(gòu)建這個(gè)客戶端的步驟:
1 編寫(xiě)客戶端
2 生成編繹這個(gè)客戶端必須要有的可移植制品。
3 編繹客戶端。
4 運(yùn)行客戶端。
5.1 編寫(xiě)客戶端
下面的程序, JAXWSClient, 是一個(gè)獨(dú)立的客戶端程序,它在這個(gè)例子所提供的代碼里可以找到。這個(gè)客戶端類(lèi)調(diào)用了部署好的服務(wù)的一個(gè) add 操作十次,從數(shù)字 0 到 9 挨個(gè)加 10.
package
client;
import
javax.xml.ws.WebServiceRef;
import
com.techtip.jaxws.sample.CalculatorService;
import
com.techtip.jaxws.sample.Calculator;
public
class
JAXWSClient
{
@WebServiceRef(wsdlLocation=
"http://localhost:8080/jaxws-webservice/CalculatorService?WSDL")
static
CalculatorServiceservice;
public
static
void
main(String[]args)
{
try
{
JAXWSClientclient=
new
JAXWSClient();
client.doTest(args);
}
catch
(Exceptione)
{
e.printStackTrace();
}
}
public
void
doTest(String[]args)
{
try
{
System.out.println(
"Retrievingportfromtheservice"+service);
Calculatorport=service.getCalculatorPort();
System.out.println(
"Invokingaddoperationonthecalculatorport");
for
(
int
i=0;i>10;i++)
{
int
ret=port.add(i,10);
if
(ret!=(i+10))
{
System.out.println("Unexpectedgreeting"+ret);
return
;
}
System.out.println(
"Adding:"+i+"+10="+ret);
}
}
catch
(Exceptione)
{
e.printStackTrace();
}
}
}
研究下上面代碼的特點(diǎn),在 JAXWSClient 類(lèi)里的 @WebServiceRef 注釋是用來(lái)定義一個(gè) web 服務(wù)的引用。 @WebServiceRef 注釋的 wsdlLocation 參數(shù)它指向了一個(gè)所要引用的服務(wù)的 WSDL 文件。 @WebServiceRef 注釋支持其它的可選屬性,就像在 JSR 224 里所說(shuō)的。靜態(tài)變量名 service 將會(huì)被客戶端容器在運(yùn)行時(shí)被動(dòng)態(tài)地注入。
注意到 JAXWSClient 的 import 語(yǔ)句:
com.techtip.jaxws.sample.CalculatorService and com.techtip.jaxws.sample.Calculator .
這些 import 語(yǔ)句是對(duì)那些在下一步里將要產(chǎn)生的可移植制品的聲明。 CalculatorService 是服務(wù)實(shí)現(xiàn)類(lèi)的可移植制品。 Calculator 是一個(gè)對(duì)于服務(wù)端點(diǎn)的 Java 接口,它是從 @WebServiceRef 注釋中的 wsdlLocation 屬性所說(shuō)明的 WSDL 文件生成的。
這個(gè)客戶端從 getWebServiceRefNamePort 方法得到一個(gè) CalculatorService ,從而得到一個(gè)端點(diǎn) Calculator 接口 Calculator port = service.getCalculatorPort();WebServiceRefName 是 @WebServiceRef 注釋的 name 屬性,或者說(shuō)是在生成的 WSDL 文件里 WSDP 端口的值。在獲得了這個(gè)端點(diǎn)后,客戶端調(diào)用了十次加的操作。
5.2 生成客戶端的可移植的制品
就像在之前所提到的, CalculatorService 跟 Calculator 都是可移植的制品。為了生成客戶端所需的所有制品,定位到 jaxws-techtip 文件夾,并且在 DOS 窗口下輸入下面的命令:
ant generate-client-artifacts
這相當(dāng)于執(zhí)行下面的 wsimport 命令 ( 都在同一行里 ) :
$GLASSFISH_HOME/bin/wsimport -keep-d ./build/classes/client
http://localhost:8080/jaxws-webservice/CalculatorService?WSDL
這將會(huì)在 jaxws-techtip 文件夾的 build/classes/client/com/techtip/jaxws/sample 目錄下生成以下的制品:
Add.java
Add.class
AddResponse.java
AddResponse.class
Calculator.java
Calculator.class
CalculatorService.java
CalculatorService.class
package-info.java
package-info.class
ObjectFactory.class
ObjectFactory.java
5.3 編繹客戶端類(lèi)
下一步需要做的工作就是編繹客戶端類(lèi)。我們可以通過(guò)輸入下面的命令來(lái)完成這項(xiàng)工作:
ant compile-client
ant 編繹任務(wù)將會(huì)編繹 client/JAXWSClient 并且把 class 文件寫(xiě)到 build /classes/client 子目錄下。它等同于運(yùn)行下面的命令 ( 都是在同一行 ) :
javac -d ./build/classes/client
-classpath $GLASSFISH_HOME/lib/javaee.jar:
$GLASSFISH_HOME/lib/appserv-ws.jar:
./build/classes/client client/JAXWSClient.java
5 . 4 運(yùn)行客戶端
為了了解這個(gè)例子是如何工作的,運(yùn)行下面的命令:
ant runtest-jaxws
它就相當(dāng)于在 build/classes/client 文件夾下, 運(yùn)行下面的命令:
$GLASSFISH_HOME/bin/appclient -mainclass client.JAXWSClient
在 DOS 窗口可以看到類(lèi)似下面的輸出:
runtest-jaxws:
[echo] Executing appclient with client class as
client.JAXWSClient
[exec]Retrieving port from the service
com.techtip.jaxws.sample.CalculatorService@162522b
[exec]Invoking add operation on the calculator port
[exec]Adding : 0 + 10 = 10
[exec]Adding : 1 + 10 = 11
[exec]Adding : 2 + 10 = 12
[exec]Adding : 3 + 10 = 13
[exec]Adding : 4 + 10 = 14
[exec]Adding : 5 + 10 = 15
[exec]Adding : 6 + 10 = 16
[exec]Adding : 7 + 10 = 17
[exec]Adding : 8 + 10 = 18
[exec]Adding : 9 + 10 = 19
all:
BUILD SUCCESSFUL
Total time: 6 seconds
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
