熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

Java遠程通信技術——Axis實戰

2013-11-23 19:02:33  來源: Java核心技術 
前言
   
    在 Internet 網絡覆蓋全球的今天網絡通信已經是當今軟件開發過程中離不開的話題在常用的WindowsLiunxUnix 系統當中大部分的網絡數據傳輸都是使用 TCP/IPUDP/IP 作為底層傳輸協議的而 HTTP 協議就是基於 TCP/IP 協議而運行的超文本傳送協議
   
    在 JAVA 高級開發語言中陸續出現 RMICORBAJAXRPCJAXWSAxisXFireHTTP InvokerHessianBurlapJMX 等遠程通信架構去實現系統之間數據傳送遠程通信技術 的一系列文章中本人將對上述復雜的 JAVA 遠程通信技術作出歸納
   
    首先在本篇文章中先對有著多年歷史的 Axis 進行介紹
   
Axis 簡介
   
    Web 服務的起源
   
    Web 服務是現今實現網絡服務概念的趨勢它把基礎架構建立於標准化的XML語言之上能夠使用一種與平台無關的方式對數據進行編碼其中 SOAP 與 WSDL 都遵從此標准化的 XML 編碼規則
   
    SOAP (Simple Object Access Protocol簡單對象訪問協議)是一種輕量的簡單的基於 XML 的協議用於描述在服務過程中服務器端與客戶端之間所交換的消息 SOAP 可以和現存的許多因特網協議和格式結合使用包括超文本傳輸協議( HTTP)簡單郵件傳輸協議(SMTP)多用途網際郵件擴充協議(MIME)
   
    WSDL (Web Service Definition LanguageWeb服務描述語言)是一種基於 XML的協議用於定義服務端與客戶端之間的契約描述Web服務的公共接口列出 Web服務進行交互時需要綁定的協議和信息格式
   
    Web 服務采用 WSDL 語言描述該服務支持的操作和信息運行時再將實際的數據以 SOAP 方式在服務端與客戶端進行信息傳遞
   
    由於軟件開發平台眾多當中存在不同的開發風格當服務器端與客戶端使用不同的開發工具時數據轉換成為復雜且關鍵的問題而 SOAP 與 WSDL 的主要特性之一在於它們都是可擴展的且與開發平台無關為了建立統一的 XML 協議 微軟IBMSunOracleBEA 等多家軟件開發商聯合起來組成了一個名為WSI(Web Service Interoperability)組織由該組織制定 WSReliableMessageWSDiscoveryWSFederationWSCoordinationWSAtomicTransactionWSBusinessActivity WSEnumerationWSEventing WSManagement 等一系列用於數據交換的規范
   
    JAXRPC JAXWS 簡介
   
    JAXRPC ( Java API for XMLbased RPC ) 是 Java 庫中基於 XML 遠程服務的一組標准 API它通過 WSDL 方式對所提供的服務進行描述並以 RPC 的風格把 SOAP 信息進行公開是 Java 庫中最早對 Web 服務提供支持的一組API
   
    JAXRPC 從其名稱可以看出最初的目的只是為了支持使用(Remote Procedure CallRPC) 的 XML 遠程過程調用操作它以 BP (WSIs Basic Profile )為基礎依賴於SAAJ (SOAP with Attachments API for Java)為規范雖然支持 SOAP 協議但對 Web 服務功能有一定的局限性於是在 年底開發團隊對 JAXRPC 進行大幅修訂由 Sun 公司組織了一個專家組開始進行 JAXRPC 規范的開發
   
    JAXRPC 是基於 JAVA 而開發的它依賴於 Annotation 等新特性在JAXRPC 的基礎上提供還增加了如異步回調面向消息等新增技術JAXRPC 以 BP (WSIs Basic Profile ) 為基礎依賴於SAAJ (SOAP with Attachments API for Java)為規范能使用 SOAP SOAP 進行信息公開它是 JAXRPC 架構發展的成果在開發完成後JAXRPC 被正式改名成為 JAXWS ( Java API for XMLWeb Services )


   
    Axis 概述
   
    Axis 全稱 Apache EXtensible Interaction System ( 阿帕奇可擴展交互系統 ) 它是一個 SOAP 引擎提供創建 Web 服務的基本框架Axis x 是基於 JAXRPC 而實現一個工具包它可以使用 HTTPJMSSMTP 等多種傳輸方式支持 SOAP 
   
    Axis x 是新一代的 Axis 引擎它支持 JAXWSJAXPRC 等 API並且在Axis x 的基礎上增加了靈活數據綁定異步調用等新增功能可使用 SOAP SOAP 協議在服務請求上Axis x 支持三種請求響應模式InOnlyRobustIn和InOut也可支持使用 REST 風格的開發方式
   
    基本的 Axis Web 服務由四部分組成Axis Servlet Axis 部署描述 遠程服務接口服務實現類
   
    Axis Servlet 是 Axis 的核心它負責 WSDL 基礎服務信息的公開並把 SOAP 請求轉化為 Java 方法的調用最後把返回值轉化為 SOAP Axis Servlet 隱藏了構建 Web 服務的大量代碼使用開發人員不用直接與 SOAP 打交道便可輕松完成 Web 服務的開發
   
    Axis 部署描述是一個XML文檔它用於管理 Web 服務的發布決定哪些服務類需要通過 SOAP 對外公開
   
    遠程服務接口並非必要的但在很多的 Web 服務開發過程中都會使用遠程服務接口用於對外暴露服務類的方法在服務器端通過服務實現類去繼承實現服務接口
   
    由於 Axis x 與 Axis x 有各自的特色下面將分開來介紹
   
    回到目錄
   
Axis x 實例
   
    Axis x 的下載與安裝
   
    Axis x 可於官網 下載完成下載後建立 Web Project 作為測試項目 把 lib 文件夾下的 jar 文件拷貝引入到測試項目當中
   
    在 webxml 文件下加入 AxisServlet 配置後系統就會對以後綴為 *jws 及路徑為 /services/* 的請求進行監聽遇到此類請求時將把信息交由  orgapacheaxistransporthttpAxisServlet 進行處理
   
    <webapp>
   
    <displayname>ApacheAxisdisplayname>
   
    <listener>
   
    <listenerclass>orgapacheaxistransporthttpAxisHTTPSessionListenerlistenerclass>
   
    listener>
   
    <servlet>
   
    <displayname>ApacheAxis Servletdisplayname>
   
    <servletname>AxisServletservletname>
   
    <servletclass>
   
    orgapacheaxistransporthttpAxisServlet
   
    servletclass>
   
    servlet>
   
   
   
    <servlet>
   
    <displayname>Axis Admin Servletdisplayname>
   
    <servletname>AdminServletservletname>
   
    <servletclass>
   
    orgapacheaxistransporthttpAdminServlet
   
    servletclass>
   
    <loadonstartup>loadonstartup>
   
    servlet>
   
   
   
    <servlet>
   
    <displayname>SOAPMonitorServicedisplayname>
   
    <servletname>SOAPMonitorServiceservletname>
   
    <servletclass>
   
    orgapacheaxismonitorSOAPMonitorService
   
    servletclass>
   
    <initparam>
   
    <paramname>SOAPMonitorPortparamname>
   
    <paramvalue>paramvalue>
   
    initparam>
   
    <loadonstartup>loadonstartup>
   
    servlet>
   
    <servletmapping>
   
    <servletname>AxisServletservletname>
   
    <urlpattern>/servlet/AxisServleturlpattern>
   
    servletmapping>
   
    <servletmapping>
   
    <servletname>AxisServletservletname>
   
    <urlpattern>*jwsurlpattern>
   
    servletmapping>
   
    <servletmapping>
   
    <servletname>AxisServletservletname>
   
    <urlpattern>/services/*urlpattern>
   
    servletmapping>
   
    <servletmapping>
   
    <servletname>SOAPMonitorServiceservletname>
   
    <urlpattern>/SOAPMonitorurlpattern>
   
    servletmapping>
   
    webapp>


   
    而 SOAPMonitorService 並非必要配置但加入SOAPMonitorService 配置可以便於對服務運行時所傳輸的SOAP信息進行監聽在服務的requestFlow或responseFlow 中加入 SOAPMonitorHandler 系統就可顯示服務請求和回發時的 SOAP 信息
   
      <deployment xmlns= 
   
    xmlns:java=>
   
   
   
    <handler name=soapmonitor type=java:orgapacheaxishandlersSOAPMonitorHandler>
   
   
   
    <parameter name=wsdlURL value=/axis/SOAPMonitorServiceimplwsdl/>
   
   
   
    <parameter name=namespace 
   
    value=implwsdl/>
   
   
   
    <parameter name=serviceName value=SOAPMonitorService/>
   
   
   
    <parameter name=portName value=Demo/>
   
   
   
    handler> 
   
    <service name=SOAPMonitorService provider=java:RPC
   
    <parameter name=allowedMethods value=publishMessage/> 
   
    <parameter name=className value=orgapacheaxismonitorSOAPMonitorService/> 
   
    <parameter name=scope value=Application/> 
   
    service> 
   
    <service name=myService provider=java:RPC
   
    <requestFlow> 
   
    <handler type=soapmonitor/> 
   
    requestFlow> 
   
    <responseFlow> 
   
    <handler type=soapmonitor/> 
   
    responseFlow> 
   
    <parameter name=allowedMethods value=*/> 
   
    <parameter name=className value=axisservermyService/> 
   
    service>  deployment>
   
    調用服務的三種方式
   
    下面從最簡單的 HelloWorld 開始介紹 Axis 的使用方法首先在 WEBINF 文件夾下建立 serverconfigwsdd 文件在 Axis x 當中此文件正是用於管理服務發布的默認配置文件首先 service 用於定義對外暴露的服務其中 name 屬性用於定義服務的名稱像下面例子當 name 為 PersonService 時對外暴露的服務路徑則對應為
   
    而 parameter 用於定義服務的相關屬性className 表示此服務的實現類而 allowedMethods 表示所公開的服務方法* 則默認為公開此類中的所有 public 公共方法而 scope 則是用於定義服務對象生成的方式它包括三個選項requestsessionapplication
   
    request 是默認選擇表示為每個請求生成一個服務對象
   
    session 表示對同一個客戶代理對象所發送的請求使用同一個服務對象並把服務信息放在同一個上下文當中當使用有狀態服務時使用此 session 更為合適在下節將再作進一步介紹
   
    application 類似於使用單體模式表示所示的請求均使用同一個服務對象當使用無狀態服務時使用 application 能有效提高運行效率
   


    最後在 transport 中定義一個 requestFlow 處理類 orgapacheaxishandlershttpURLMapper表示在系統接受到 http 請求時將會調用 URLMapper 類來處理路徑映射等問題
   
    <deployment xmlns=
   
    xmlns:java=>
   
   
   
    <service name=PersonService provider=java:RPC>
   
   
   
    <parameter name=className  value=axisserviceImplsPersonServiceImpl />
   
    <parameter name=allowedMethods value=* />
   
    <parameter name=scope  value=application />
   
    service>
   
   
   
    <transport name=http>
   
    <requestFlow>
   
    <handler type=java:orgapacheaxishandlershttpURLMapper/>
   
    requestFlow>
   
    transport>  deployment>
   
    PersonService 服務代碼如下此時運行服務輸入路徑 浏覽器上將顯示此服務的 wsdl 信息
   
      public interface IPersonService {
   
    String HelloWorld(String name)   }
   
      public class PersonServiceImpl  implements IPersonService { 
   
    @Override
   
   
   
    public String HelloWorld(string name){
   
    return Hello +name;
   
    }  }
   
    客戶端的生成工具有多種其中一種是使用 Axis x 中的自帶生成器 WSDLJava 此生成器可以根據 wsdl 文件生成客戶端
   
    首先在環境變量中把 Axis_Home 綁定到 Axis x 的根目錄在 path 加入設置  ;%Axis_Home%\lib 然後輸入
   
    Java orgapacheaxiswsdlWSDLJava p axisclientperson
   
    此時系統將在 axisclientperson 包內生成客戶端代碼類 PersonServiceImplPersonServiceImplServicePersonServiceImplServiceLocatorPersonServiceSoapBindingStub
   
    PersonServiceImplServiceLocator 用於實現 PersonServiceImplService 接口它綁定了服務的名稱地址端口等詳細資料
   
    PersonServiceImpl 用於定義服務的接口而 PersonServiceSoapBindingStub 則是此服務代理它通過 SOAP 協議把操作請求發送到服務器並把返回信息轉化為 Java 對象
   
   
   
    public static void main(String[] args) throws 
   
    RemoteException MalformedURLException ServiceException {
   
    // TODO Autogenerated method stub
   
    HelloWorld()
   
    }
   
   
   
    private static void HelloWorld() throws 
   
    RemoteException MalformedURLException{
   
    PersonServiceImpl personService=new PersonServiceSoapBindingStub(
   
    new URL(
   
    new PersonServiceImplServiceLocator())
   
    Systemoutprintln(personServicehelloWorld(Leslie))
   
    }
   
    通過系統自動生成的代理類就能簡單地調用遠程服務這是因為在代理類中已經完成了大量關於PersonService 服務的配置但本人覺得想要深入地了解 Axis 的開發就應該了解其內部的結構所以在下面例子當中將介紹如何使用Axis的內部機制直接調用Web服務


   
    在 orgapacheaxisclient 中存在著服務的基礎類 Service 通過 Service 可用於管理服務的綁定地址端點獲取服務的 WSDL 等詳細信息另外 Call 類用於管理每個服務請求動作它可以設置每個請求的方法最後通過callinvoke(Object[])調用服務並獲取完成後的返回值
   
   
   
    public static void main(String[] args) throws 
   
    RemoteException MalformedURLException ServiceException {
   
    HelloWorld()
   
    }  
   
    private static void HelloWorld() throws
   
    ServiceExceptionRemoteException{
   
    //生成服務對象Service
   
    Service service=new Service()
   
    Call call=(Call) servicecreateCall()
   
    //設置Endpoint地址
   
    callsetTargetEndpointAddress(
   
   
   
    //綁定請求方法名稱
   
    callsetOperationName(HelloWorld
   
    //通過callinvoke調用服務獲取返回值
   
    String data=(String)callinvoke(new Object[]{Leslie})
   
    Systemoutprintln(data)
   
    }
   
    如果覺得使用 Call 實現請求較為麻煩Service 中還提供一個 getPort 方法通過此方法還可直接實現服務接口 PersonServiceImpl另外Axis 還為准備了一個 ServiceFactory 工廠通過 ServiceFactory 可以直接獲取 Service 對象
   
   
   
    public static void main(String[] args) throws 
   
    RemoteException MalformedURLException ServiceException {
   
    // TODO Autogenerated method stub
   
    HelloWorld()
   
    }  
   
    private static void HelloWorld() throws 
   
    ServiceException RemoteException MalformedURLException {
   
    String wsdl=;
   
    String uri=;
   
    String serviceName=PersonServiceImplService;
   
   
   
    //使用serviceFacotry直接生成服務
   
    ServiceFactory factory=ServiceFactorynewInstance()
   
    Service service=(Service) factorycreateService(
   
    new URL(wsdl)new QName(uriserviceName))
   
   
   
    //使用servicegetPort方法實現服務接口
   
    PersonServiceImpl personService=(PersonServiceImpl)service
   
    getPort(PersonServiceImplclass)
   
    String data=oWorld(Leslie
   
    Systemoutprintln(data)
   
    }
   
    以自定義對象傳輸數據
   
    若需要以自定義對象作為數據傳輸的載體則需要為自定義對象繼承 Serializable 接口另外可以留意一下服務的 wsdl 因為 Axis 並沒有默認使用List Map 等類型 在 ListMap 等作為參數時wsdl 都會把返回類型設置為 ArrayOf_xsd_anyType所以建議使用簡單數組作為返回值
   
    public class PersonEntity implements Serializable {
   
    private Integer id;
   
    private String name;
   
    private Integer age;
   
    private String address;
   
   
   
    public PersonEntity(Integer idString nameInteger ageString address){
   
    thisid=id;
   
    thisname=name;
   
    thisage=age;
   
    thisaddress=address;
   
    }
   
   
   
    public Integer getId(){
   
    return id;
   
    }
   
   
   
    public void setId(Integer id){
   
    thisid=id;
   
    }
   
    ……  }    public interface IPersonService {
   
    PersonEntity GetPerson(int id)
   
    PersonEntity[] GetList()
   
    List GetList(String name)  }    public class PersonServiceImpl implements IPersonService {
   
    @Override
   
    public PersonEntity[] GetList(){
   
    PersonEntity[] list=new PersonEntity[];
   
    PersonEntity person=new PersonEntity(Leslietianhe
   
    PersonEntity person=new PersonEntity(Elvahenan
   
    list[]=person;
   
    list[]=person;
   
    return list;
   
    }
   
   
   
    @Override
   
    public List GetList(String name){
   
    List list=new ArrayList()
   
    PersonEntity person=new PersonEntity(name+ Leetianhe
   
    PersonEntity person=new PersonEntity(name+ Chenhenan
   
    listadd(person
   
    listadd(person
   
    return list;
   
    }
   
   
   
    @Override
   
    public PersonEntity GetPerson(int id){
   
    return new PersonEntity(idLeslietianhe
   
    }  }
   
    在 serverconfigwsdd 中使用 beanMapping 加入自定義對象綁定以 languageSpecificType 綁定類名qname 可由用戶設置但必須與 xmln 特性相對應
   
   
   
    ……
   
    <service name=PersonService provider=java:RPC>
   
    <parameter name=className  value=axisserviceImplsPersonServiceImpl />
   
    <parameter name=allowedMethods value=* />
   
    <parameter name=scope  value=application />
   
    <beanMapping qname=myNS:PersonEntity xmlns:myNS=urn:PersonEntity
   
    languageSpecificType=java:axisentityPersonEntity />
   
    service>
   
    ……
   


    以 WSDLJava 生成客戶端代碼後可以留意 PersonEntity 對象已經自動實現了 Serializable 接口增加了 getDeserializergetSerializer 等序列化與反序列化方法此時直接使用代理類會自動地完成對象序列化的過程可以節省了不少時間
   
   
   
    public static void main(String[] args) throws 
   
    RemoteException MalformedURLException ServiceException {
   
    GetList()
   
    GetPerson()
   
    }
   
   
   
   
   
    private static void GetPerson() throws 
   
    RemoteException MalformedURLException{
   
    PersonServiceImpl personService=new PersonServiceSoapBindingStub(
   
    new URL(
   
    new PersonServiceImplServiceLocator())
   
    PersonEntity person=personServicegetPerson(
   
    DisplayPersonProperty(person)
   
    }
   
    private static void GetList() throws
   
    ServiceException RemoteException MalformedURLException{
   
    PersonServiceImpl personService=new PersonServiceSoapBindingStub(
   
    new URL(
   
    new PersonServiceImplServiceLocator())
   
    Object[] objs=personServicegetList(Leslie
   
    for(Object person:objs)
   
    DisplayPersonProperty((PersonEntity)person)
   
    }
   
    //顯示對象屬性
   
    private static void DisplayPersonProperty(PersonEntity person){
   
    Systemoutprintln(Id:+persongetId()+  Name:+persongetName()+  Age:+
   
    persongetAge()+  Address:+persongetAddress())
   
    }
   
    但需要注意如果使用 Service 類去調用服務的時候需要使用 CallregisterTypeMapping 注冊一個類型把接收到的信息轉換為 PersonEntity 類型在注冊類型時 namespaceURI 參數值需要與服務端 serverconfigwsdd 中的值保持一致
   
   
   
    public static void main(String[] args) throws 
   
    RemoteException MalformedURLException ServiceException {
   
    // TODO Autogenerated method stub
   
    GetArray()
   
    GetList()
   
    }
   
     
   
    private static void GetArray() throws 
   
    ServiceException RemoteException{
   
    Service service=new Service()
   
    Call call=(Call)servicecreateCall()
   
    callsetTargetEndpointAddress(
   
   
   
   
   
    //注冊返回類型namespaceURI 必須與服務端注冊值一致
   
    QName qName=new QName(urn:PersonEntityPersonEntity
   
   
   
    callregisterTypeMapping(PersonEntityclass qName
   
    new BeanSerializerFactory(PersonEntityclassqName
   
    new BeanDeserializerFactory(PersonEntityclassqName))
   
   
   
    //綁定請求方法
   
    callsetOperation(GetList
   
   
   
    //設置返回類型
   
    callsetReturnClass(PersonEntity[]class)
   
    PersonEntity[] list=(PersonEntity[]) callinvoke(new Object[]{})
   
    for(PersonEntity person:list)
   
    DisplayPersonProperty(person)
   
    }
   
   
   
    private static void GetList() throws
   
    ServiceException RemoteException{
   
    Service service=new Service()
   
    Call call=(Call)servicecreateCall()
   
    callsetTargetEndpointAddress(
   
   
   
   
   
    //注冊返回類型namespaceURI 必須與服務端注冊值一致
   
    QName qName=new QName(urn:PersonEntityPersonEntity
   
   
   
    callregisterTypeMapping(PersonEntityclass qName
   
    new BeanSerializerFactory(PersonEntityclassqName
   
    new BeanDeserializerFactory(PersonEntityclassqName))
   
   
   
    //綁定請求方法
   
    callsetOperationName(new javaxxmlnamespac


From:http://tw.wingwit.com/Article/program/Java/hx/201311/26177.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.