1. 程式人生 > >webservice遠端呼叫詳解

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)