webservice遠端呼叫詳解
webservice是跨程式語言和跨平臺的遠端呼叫技術。常見的遠端呼叫技術還有RMI,因為webservice跨平臺和跨程式語言,因此應用更廣泛,但效能略低。
遠端呼叫:一臺計算機a上的一個程式可以呼叫另一臺計算機b上的一個物件的方法。
關於Java webService框架,主要有AXIS、XFire、CXF,還有Java自帶的JAX-WS(必須JDK6以上環境)。
SOAP:是在分散式的環境中交換資訊的簡單協議,以XML作為資料傳送的方式。
SOAP=RPC+HTTP+XML
SOAP RPC的工作原理:類似於web的請求/響應方式,不同之處在於web客戶和web伺服器之間傳輸的是HTML資料。在SOAP RPC模式中,SOAP客戶(程式)和SOAP服務之間傳輸的是符合SOAP規範的XML資料。(XML中說明呼叫遠端服務物件的哪個方法、傳遞的引數是什麼,以及服務物件的返回結果是什麼。)
WSDL:webservice客戶端要呼叫一個webservice服務,首先要知道這個服務的地址在哪,以及這個服務有什麼方法可以呼叫。因此webservice服務端首先要通過一個WSDL檔案來說明有什麼服務可以對外呼叫,服務是什麼,有哪些方法,方法接受的引數是什麼,返回值是什麼。
WSDL檔案儲存在服務端,可以通過url地址訪問到。客戶端要呼叫一個webservice服務之前,要知道該服務的WSDL檔案的地址。webservice服務提供者可以通過兩種方式暴露它的WSDL檔案地址:
a、註冊到UDDI伺服器,以便被人查詢;
b、直接告訴客戶端呼叫者;
要訪問一個遠端的webservice,有兩種方法:
a、通過SOAP協議;
b、通過REST的方式;
1、AXIS是apache軟體組織對SOAP規範的實現。
SOAP客戶程式——>AXIS API—RPC請求—>AXIS web應用(SOAP服務),此web應用可以放在Tomcat容器中。
在AXIS上建立和釋出基於RPC的SOAP服務步驟:
a、建立實現SOAP服務的java類;
b、建立SOAP服務的釋出描述檔案;
c、通過AXIS的AdminClient客戶程式釋出SOAP服務;
一個web容器中的web應用———遠端訪問———>另一個web容器中的AXIS應用(SOAP服務)
2、web服務開源框架XFire
XFire是下一代的java soap開源框架。XFire提供了方便的API,使用這些API可以開發面向服務(SOA)的程式。
主要特性包括:
a、支援多個重要的webservice標準,包括SOAP、WSDL等。
b、支援JSR181,可以通過JDK5中的註解配置web服務。
c、支援基於HTTP、JMS等多種協議訪問web服務。
d、支援spring、Pico等多種容器。
e、支援客戶端和伺服器程式碼生成。
XFire在1.2.6版本後與Celtix合併成為apache的CXF專案,主頁為http://cxf.apache.org。
到XFire主頁下載xfire-distribution-1.2.6.zip。解壓後得到目錄結構為:
api目錄:是XFire框架中所有類對應的Java Doc文件。
lib目錄:XFire執行所依賴的jar包。
manual目錄: 包含有XFire框架的幫助文件,可以從中學習更多運用XFire框架實現SOA的知識和技巧。
xFire-all-1.2.6.jar:XFire框架的jar包,包括了全部的模組。
其中lib目錄中的jar包和xFire-all-1.2.6.jar是XFire執行所必須的類庫。
(1)在Myeclipse中釋出web服務
a、新建一個web工程,匯入XFire執行所必須的jar包。如:XFireDemo
b、建立服務的介面及實現類。
c、在web .xml檔案中,配置XFire的servlet。
如:
定義在web.xml中的XFireServlet負責提供web服務,且提供WSDL。
d、在工程下,新建WebServices/services.xml檔案。(該配置檔案定義了一個web服務)
如:
該配置檔案為XFire釋出服務的配置檔案,當請求服務時,XFire會根據這個配置檔案解析對應的服務。
e、將此web工程釋出到Tomcat中。
(2)在Myeclipse中呼叫web服務
當web服務釋出後,在客戶端有多種方式呼叫。如Myeclipse客戶端、SDK方式的客戶端和根據WSDL自動生成的客戶端。
(3)XFire與spring整合(XFire執行在spring容器中)
XFire提供了對spring的整合,可配置spring bean來提供web服務。
a、配置spring bean
在web.xml檔案中增加spring的配置,同時將XFire的bean配置檔案加入到spring容器中。
b、配置XFire Servlet
在spring容器中,需配置org.codehaus.xfire.spring.XFireSpringServlet類集中處理web服務的servlet請求。
c、配置web服務Bean
最後配置spring容器中的bean,此時XFire執行在spring容器中,故不再需要配置servicers.xml檔案,而是在applicationContext.xml配置bean。
(4)web服務安全
作為一個服務提供商,所提供的服務若沒有安全機制,則任何人都可以使用服務了。
數字簽名(signature)其實是使用私鑰對報文的摘要進行加密,只有報文在傳輸過程中不被篡改,接收端在進行數字簽名驗證時才可能成功。
雖然數字簽名解決了完整性和不可抵賴性的安全問題,但訊息體還是以明文的方式進行傳送,在傳輸過程中,訊息體的內容可能被監視。此時需要加密(encryption)。
3、CXF與Spring整合
(1)In Action
新建web工程,如cxftest。在pom.xml中新增依賴:groupId為org.apache.cxf,artifactId分別為cxf-rt-frontend-jaxws和cxf-rt-transports-http,version為2.6.2。
a、定義介面,必須加上@webservice註解,否則會報錯。如:
@WebService(name="HelloService", targetNamespace="http://test.com")
publicinterface HelloService {
@WebMethod
@WebResult(name = "result")
public String sayHello(@WebParam(name = "s")String s);
}
b、實現類,其中@WebService註解表示是要釋出的web服務,endpointInterface的值是該服務類對應的介面。如:
@WebService(name="HelloService", targetNamespace="http://test.com",endpointInterface = "com.framework.webservice.HelloService")
publicclass HelloServiceImpl implements HelloService{
public String sayHello(String s) {
System.out.println( "Insist on"+s);
return"Insist on";
}
}
c、spring配置檔案
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
<importresource="classpath:META-INF/cxf/cxf.xml"/>
<importresource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
<importresource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<bean id="helloServiceImpl" class="com.framework.webservice.HelloServiceImpl" />
<jaxws:endpointid="hello"implementor="#helloServiceImpl"address="/Hello"/>
</beans>
implementor:指明具體的實現類;address:指明這個webservice的相對地址。
d、web.xml檔案中加入,如:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/applicationContext.xml</param-value> //載入spring配置檔案
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
f、建立客戶端呼叫webservice測試
//建立WebService客戶端代理工廠
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
//註冊WebService介面
factory.setServiceClass(HelloService.class);
//設定WebService地址
HelloService hello = (HelloService)factory.create();
//呼叫webservice介面方法
hello.sayHello("hello");//返回Insist on
3、PS
(1)在另一個web應用中呼叫webservice有兩種方法:
一、
a、定義介面
@WebService(name="HelloService", targetNamespace="http://test.com")
publicinterface HelloService {
@WebMethod
@WebResult(name = "result")
public String sayHello(@WebParam(name = "s")String s);
}
b、在applicationContext.xml檔案中加入:
<importresource="classpath:META-INF/cxf/cxf.xml"/>
<importresource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
<importresource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<jaxws:client id="helloClient" serviceClass="com.framework.webservice.client.HelloService" address="http://localhost:8080/cxftest/Hello" />
c、在action中引用:
@Resource(name="helloClient")
private HelloService helloService;
之後,就可以在此action中呼叫此HelloService中的方法取得資料了;
二、
a、定義介面
@WebService(name="HelloService", targetNamespace="http://test.com")
publicinterface HelloService {
@WebMethod
@WebResult(name = "result")
public String sayHello(@WebParam(name = "s")String s);
}
b、在applicationContext.xml檔案中加入:
<importresource="classpath:META-INF/cxf/cxf.xml"/>
<importresource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
<importresource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<bean id="helloService" class="com.framework.webservice.HelloService" factory-bean="helloClientFactory" factory-method="create"/>
<bean id="helloClientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass" value="com.framework.webservice.HelloService" />
</bean>
c、在action中引用:
@Resource(name="helloService")
private HelloService helloService;
之後,就可以在此action中呼叫此HelloService中的方法取得資料了;
(2) 客戶端呼叫進行身份驗證:
<!-- 使用攔截器配置示例-->
<jaxws:client id="client" serviceClass="com.dahua.icp.webservice.caze.CazeService" address="http://localhost:8080/tz/ws/caze" >
<jaxws:outInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
<bean class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor" />
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken" />
<entry key="passwordType" value="PasswordText" />
<entry key="user" value="cxfClient" />
<entry key="passwordCallbackRef">
<ref bean="clientPasswordCallback" />
</entry>
</map>
</constructor-arg>
</bean>
</jaxws:outInterceptors>
</jaxws:client>
(3)