<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Java遠程通信技術(shù)——Axis實戰(zhàn)

    前言

    在 Internet 網(wǎng)絡(luò)覆蓋全球的今天,網(wǎng)絡(luò)通信已經(jīng)是當(dāng)今軟件開發(fā)過程中離不開的話題。在常用的Windows、Liunx、Unix 系統(tǒng)當(dāng)中,大部分的網(wǎng)絡(luò)數(shù)據(jù)傳輸都是使用 TCP/IP、UDP/IP 作為底層傳輸協(xié)議的,而 HTTP 協(xié)議就是基于 TCP/IP 協(xié)議而運行的超文本傳送協(xié)議。
    在 JAVA 高級開發(fā)語言中,陸續(xù)出現(xiàn) RMI、CORBA、JAX-RPC、JAX-WS、Axis、XFire、HTTP Invoker、Hessian、Burlap、JMX 等遠程通信架構(gòu)去實現(xiàn)系統(tǒng)之間數(shù)據(jù)傳送。在 “遠程通信技術(shù)” 的一系列文章中,本人將對上述復(fù)雜的 JAVA 遠程通信技術(shù)作出歸納。
    首先,在本篇文章中先對有著10多年歷史的 Axis 進行介紹。

     

    目錄

    一、Axis 簡介

    二、Axis 1.x 實例

    三、Web 服務(wù)會話管理

    四、自定義Handler

    五、新一代 SOAP 引擎 Axis 2.x

    六、AXIOM 對象模型

    七、Module 模塊獨立化處理方式

    八、異步調(diào)用Web服務(wù)

     

     


    一、Axis 簡介

    1.1 Web 服務(wù)的起源

    Web 服務(wù)是現(xiàn)今實現(xiàn)網(wǎng)絡(luò)服務(wù)概念的趨勢,它把基礎(chǔ)架構(gòu)建立于標(biāo)準(zhǔn)化的XML語言之上,能夠使用一種與平臺無關(guān)的方式對數(shù)據(jù)進行編碼,其中 SOAP 與 WSDL 都遵從此標(biāo)準(zhǔn)化的 XML 編碼規(guī)則。
    SOAP (Simple Object Access Protocol,簡單對象訪問協(xié)議)是一種輕量的、簡單的、基于 XML 的協(xié)議,用于描述在服務(wù)過程中服務(wù)器端與客戶端之間所交換的消息。 SOAP 可以和現(xiàn)存的許多因特網(wǎng)協(xié)議和格式結(jié)合使用,包括超文本傳輸協(xié)議( HTTP),簡單郵件傳輸協(xié)議(SMTP),多用途網(wǎng)際郵件擴充協(xié)議(MIME)。
    WSDL (Web Service Definition Language,Web服務(wù)描述語言)是一種基于 XML的協(xié)議,用于定義服務(wù)端與客戶端之間的契約,描述Web服務(wù)的公共接口,列出 Web服務(wù)進行交互時需要綁定的協(xié)議和信息格式。
    Web 服務(wù)采用 WSDL 語言描述該服務(wù)支持的操作和信息,運行時再將實際的數(shù)據(jù)以 SOAP 方式在服務(wù)端與客戶端進行信息傳遞。
    由于軟件開發(fā)平臺眾多,當(dāng)中存在不同的開發(fā)風(fēng)格,當(dāng)服務(wù)器端與客戶端使用不同的開發(fā)工具時,數(shù)據(jù)轉(zhuǎn)換成為復(fù)雜且關(guān)鍵的問題。而 SOAP 與 WSDL 的主要特性之一在于它們都是可擴展的,且與開發(fā)平臺無關(guān)。為了建立統(tǒng)一的 XML 協(xié)議, 微軟、IBM、Sun、Oracle、BEA 等多家軟件開發(fā)商聯(lián)合起來,組成了一個名為WS-I(Web Service Interoperability)組織,由該組織制定 WS-ReliableMessage、WS-Discovery、WS-Federation、WS-Coordination、WS-AtomicTransaction、WS-BusinessActivity 、WS-Enumeration、WS-Eventing 、WS-Management 等一系列用于數(shù)據(jù)交換的規(guī)范。

    1.2 JAX-RPC 、JAX-WS 簡介

    JAX-RPC ( Java API for XML-based RPC ) 是 Java 庫中基于 XML 遠程服務(wù)的一組標(biāo)準(zhǔn) API,它通過 WSDL 方式對所提供的服務(wù)進行描述,并以 RPC 的風(fēng)格把 SOAP 信息進行公開,是 Java 庫中最早對 Web 服務(wù)提供支持的一組API。
    JAX-RPC 1.0 從其名稱可以看出,最初的目的只是為了支持使用(Remote Procedure Call,RPC) 的 XML 遠程過程調(diào)用操作,它以 BP 1.0 (WS-I’s Basic Profile 1.0)為基礎(chǔ),依賴于SAAJ 1.2(SOAP with Attachments API for Java)為規(guī)范,雖然支持 SOAP 協(xié)議,但對 Web 服務(wù)功能有一定的局限性。于是在 2003 年底,開發(fā)團隊對 JAX-RPC 1.0 進行大幅修訂,由 Sun 公司組織了一個專家組開始進行 JAX-RPC 2.0 規(guī)范的開發(fā)。
    JAX-RPC 2.0 是基于 JAVA 5 而開發(fā)的,它依賴于 Annotation 等新特性,在JAX-RPC 的基礎(chǔ)上提供還增加了如異步回調(diào),面向消息等新增技術(shù)。JAX-RPC 2.0 以 BP 1.1(WS-I’s Basic Profile 1.1 ) 為基礎(chǔ),依賴于SAAJ 1.3(SOAP with Attachments API for Java)為規(guī)范,能使用 SOAP 1.1、SOAP 1.2 進行信息公開。它是 JAX-RPC 1.1 架構(gòu)發(fā)展的成果,在開發(fā)完成后,JAX-RPC 2.0 被正式改名成為 JAX-WS ( Java API for XML-Web Services ) 。

     

    1.3 Axis 概述

    Axis 全稱 Apache EXtensible Interaction System ( 阿帕奇可擴展交互系統(tǒng) ) , 它是一個 SOAP 引擎,提供創(chuàng)建 Web 服務(wù)的基本框架。Axis 1.x 是基于 JAX-RPC 而實現(xiàn)一個工具包,它可以使用 HTTP、JMS、SMTP 等多種傳輸方式支持 SOAP  。
    Axis 2.x 是新一代的 Axis 引擎,它支持 JAX-WS、JAX-PRC 等 API,并且在Axis 1.x 的基礎(chǔ)上增加了靈活數(shù)據(jù)綁定、異步調(diào)用等新增功能,可使用 SOAP 1.1 、SOAP 1.2 協(xié)議。在服務(wù)請求上,Axis 2.x 支持三種請求-響應(yīng)模式:In-Only、Robust-In和In-Out,也可支持使用 REST 風(fēng)格的開發(fā)方式。
    基本的 Axis Web 服務(wù)由四部分組成:Axis Servlet 、Axis 部署描述、 遠程服務(wù)接口、服務(wù)實現(xiàn)類。
    Axis Servlet 是 Axis 的核心,它負責(zé) WSDL 基礎(chǔ)服務(wù)信息的公開,并把 SOAP 請求轉(zhuǎn)化為 Java 方法的調(diào)用,最后把返回值轉(zhuǎn)化為 SOAP 。Axis Servlet 隱藏了構(gòu)建 Web 服務(wù)的大量代碼,使用開發(fā)人員不用直接與 SOAP 打交道便可輕松完成 Web 服務(wù)的開發(fā)。
    Axis 部署描述是一個XML文檔,它用于管理 Web 服務(wù)的發(fā)布,決定哪些服務(wù)類需要通過 SOAP 對外公開 。
    遠程服務(wù)接口并非必要的,但在很多的 Web 服務(wù)開發(fā)過程中都會使用遠程服務(wù)接口用于對外暴露服務(wù)類的方法,在服務(wù)器端通過服務(wù)實現(xiàn)類去繼承實現(xiàn)服務(wù)接口。
    由于 Axis 1.x 與 Axis 2.x 有各自的特色,下面將分開來介紹。

    回到目錄

    二、Axis 1.x 實例

    2.1 Axis 1.x 的下載與安裝

    Axis 1.x 可于官網(wǎng) http://axis.apache.org/axis/ 下載,完成下載后建立 Web Project 作為測試項目 ,把 lib 文件夾下的 jar 文件拷貝,引入到測試項目當(dāng)中。
    在 web.xml 文件下加入 AxisServlet 配置后,系統(tǒng)就會對以后綴為 *.jws 及路徑為 /services/* 的請求進行監(jiān)聽,遇到此類請求時將把信息交由  org.apache.axis.transport.http.AxisServlet 進行處理。

     1 <web-app>
     2     <display-name>Apache-Axis</display-name>
     3     <listener>
     4       <listener-class>org.apache.axis.transport.http.AxisHTTPSessionListener</listener-class>
     5     </listener>
     6     <servlet>
     7       <display-name>Apache-Axis Servlet</display-name>
     8       <servlet-name>AxisServlet</servlet-name>
     9       <servlet-class>
    10           org.apache.axis.transport.http.AxisServlet
    11       </servlet-class>
    12     </servlet>
    13     <!-- 服務(wù)管理 -->
    14     <servlet>
    15       <display-name>Axis Admin Servlet</display-name>
    16       <servlet-name>AdminServlet</servlet-name>
    17       <servlet-class>
    18           org.apache.axis.transport.http.AdminServlet
    19       </servlet-class>
    20       <load-on-startup>100</load-on-startup>
    21     </servlet>
    22     <!-- 對輸入輸出的SOAP信息進行檢測 -->
    23     <servlet>
    24       <display-name>SOAPMonitorService</display-name>
    25       <servlet-name>SOAPMonitorService</servlet-name>
    26       <servlet-class>
    27           org.apache.axis.monitor.SOAPMonitorService
    28       </servlet-class>
    29       <init-param>
    30         <param-name>SOAPMonitorPort</param-name>
    31         <param-value>5001</param-value>
    32       </init-param>
    33       <load-on-startup>100</load-on-startup>
    34     </servlet>
    35     <servlet-mapping>
    36       <servlet-name>AxisServlet</servlet-name>
    37       <url-pattern>/servlet/AxisServlet</url-pattern>
    38     </servlet-mapping>
    39     <servlet-mapping>
    40       <servlet-name>AxisServlet</servlet-name>
    41       <url-pattern>*.jws</url-pattern>
    42     </servlet-mapping>
    43     <servlet-mapping>
    44       <servlet-name>AxisServlet</servlet-name>
    45       <url-pattern>/services/*</url-pattern>
    46     </servlet-mapping>
    47     <servlet-mapping>
    48       <servlet-name>SOAPMonitorService</servlet-name>
    49       <url-pattern>/SOAPMonitor</url-pattern>
    50     </servlet-mapping>
    51   </web-app>

    而 SOAPMonitorService 并非必要配置,但加入SOAPMonitorService 配置,可以便于對服務(wù)運行時所傳輸?shù)腟OAP信息進行監(jiān)聽,在服務(wù)的requestFlow或responseFlow 中加入 SOAPMonitorHandler , 系統(tǒng)就可顯示服務(wù)請求和回發(fā)時的 SOAP 信息。

     1  <deployment xmlns="http://xml.apache.org/axis/wsdd/" 
     2              xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">  
     3         <handler name="soapmonitor" type="java:org.apache.axis.handlers.SOAPMonitorHandler">  
     4             <parameter name="wsdlURL" value="/axis/SOAPMonitorService-impl.wsdl"/>  
     5             <parameter name="namespace" 
     6              value="http://tempuri.org/wsdl/2001/12/SOAPMonitorService-impl.wsdl"/>  
     7             <parameter name="serviceName" value="SOAPMonitorService"/>  
     8             <parameter name="portName" value="Demo"/>  
     9         </handler>  
    10         <service name="SOAPMonitorService" provider="java:RPC">  
    11             <parameter name="allowedMethods" value="publishMessage"/>  
    12             <parameter name="className" value="org.apache.axis.monitor.SOAPMonitorService"/>  
    13             <parameter name="scope" value="Application"/>  
    14         </service>  
    15 
    16      <service name="myService" provider="java:RPC">  
    17         <requestFlow>  
    18             <handler type="soapmonitor"/>  
    19         </requestFlow>  
    20         <responseFlow>  
    21             <handler type="soapmonitor"/>  
    22         </responseFlow>  
    23         <parameter name="allowedMethods" value="*"/>  
    24         <parameter name="className" value="axis.server.myService"/>  
    25     </service>  
    26 </deployment>  

     

    2.2 調(diào)用服務(wù)的三種方式

    下面從最簡單的 HelloWorld 開始,介紹 Axis 的使用方法。首先在 WEB-INF 文件夾下建立 server-config.wsdd 文件,在 Axis 1.x 當(dāng)中,此文件正是用于管理服務(wù)發(fā)布的默認配置文件。首先 service 用于定義對外暴露的服務(wù),其中 name 屬性用于定義服務(wù)的名稱。像下面例子,當(dāng) name 為 PersonService 時,對外暴露的服務(wù)路徑則對應(yīng)為 http://localhost:8080/axis.server/services/PersonService
    而 parameter 用于定義服務(wù)的相關(guān)屬性,className 表示此服務(wù)的實現(xiàn)類,而 allowedMethods 表示所公開的服務(wù)方法,“*" 則默認為公開此類中的所有 public 公共方法。而 scope 則是用于定義服務(wù)對象生成的方式,它包括三個選項:request、session、application 。
    request 是默認選擇,表示為每個請求生成一個服務(wù)對象;
    session 表示對同一個客戶代理對象所發(fā)送的請求使用同一個服務(wù)對象,并把服務(wù)信息放在同一個上下文當(dāng)中。當(dāng)使用有狀態(tài)服務(wù)時,使用此 session 更為合適,在下節(jié)將再作進一步介紹;
    application 類似于使用單體模式,表示所示的請求均使用同一個服務(wù)對象,當(dāng)使用無狀態(tài)服務(wù)時使用 application 能有效提高運行效率。
    最后在 transport 中定義一個 requestFlow 處理類 org.apache.axis.handlers.http.URLMapper,表示在系統(tǒng)接受到 http 請求時,將會調(diào)用 URLMapper 類來處理路徑映射等問題。

     1 <deployment xmlns="http://xml.apache.org/axis/wsdd/"
     2              xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
     3     <!--在瀏覽器暴露服務(wù) PersonService-->
     4     <service name="PersonService" provider="java:RPC">
     5          <!--綁定服務(wù)實現(xiàn)類型 PersonServiceImpl-->
     6         <parameter name="className"  value="axis.serviceImpls.PersonServiceImpl" />
     7         <parameter name="allowedMethods" value="*" />
     8         <parameter name="scope"  value="application" />
     9     </service>
    10     <!--當(dāng)接收到 http 請求時交由 URLMapper 進行處理-->
    11     <transport name="http">
    12         <requestFlow>
    13             <handler type="java:org.apache.axis.handlers.http.URLMapper"/>
    14         </requestFlow>
    15     </transport>
    16  </deployment>

    PersonService 服務(wù)代碼如下,此時運行服務(wù),輸入路徑 http://localhost:8080/axis.server/services/PersonService?wsdl ,瀏覽器上將顯示此服務(wù)的 wsdl 信息。

     1  public interface IPersonService {
     2      String HelloWorld(String name);
     3  }
     4  
     5  public class PersonServiceImpl  implements IPersonService { 
     6      @Override  
     7      public String HelloWorld(string name){
     8          return "Hello "+name;
     9      }
    10  }

    客戶端的生成工具有多種,其中一種是使用 Axis 1.x 中的自帶生成器 WSDL2Java ,此生成器可以根據(jù) wsdl 文件生成客戶端。
    首先在環(huán)境變量中把 Axis_Home 綁定到 Axis 1.x 的根目錄,在 path 加入設(shè)置  ".;%Axis_Home%\lib ", 然后輸入
    Java org.apache.axis.wsdl.WSDL2Java http://localhost:8080/axis.server/services/PersonService?wsdl -p axis.client.person
    此時系統(tǒng)將在 axis.client.person 包內(nèi)生成客戶端代碼類 PersonServiceImpl、PersonServiceImplService、PersonServiceImplServiceLocator、PersonServiceSoapBindingStub。
    PersonServiceImplServiceLocator 用于實現(xiàn) PersonServiceImplService 接口,它綁定了服務(wù)的名稱,地址,端口等詳細資料。
    PersonServiceImpl 用于定義服務(wù)的接口,而 PersonServiceSoapBindingStub 則是此服務(wù)代理,它通過 SOAP 協(xié)議把操作請求發(fā)送到服務(wù)器,并把返回信息轉(zhuǎn)化為 Java 對象。

     1     public static void main(String[] args) throws 
     2         RemoteException, MalformedURLException, ServiceException {
     3         // TODO Auto-generated method stub
     4          HelloWorld();
     5     }
     6     
     7     private static void HelloWorld() throws 
     8         RemoteException, MalformedURLException{
     9         PersonServiceImpl personService=new PersonServiceSoapBindingStub(
    10             new URL("http://localhost:8080/axis.server/services/PersonService"),
    11             new PersonServiceImplServiceLocator());
    12         System.out.println(personService.helloWorld("Leslie"));
    13     }

    通過系統(tǒng)自動生成的代理類就能簡單地調(diào)用遠程服務(wù),這是因為在代理類中已經(jīng)完成了大量關(guān)于PersonService 服務(wù)的配置,但本人覺得想要深入地了解 Axis 的開發(fā),就應(yīng)該了解其內(nèi)部的結(jié)構(gòu)。所以在下面例子當(dāng)中將介紹如何使用Axis的內(nèi)部機制直接調(diào)用Web服務(wù)。
    在 org.apache.axis.client 中存在著服務(wù)的基礎(chǔ)類 Service ,通過 Service 可用于管理服務(wù)的綁定地址,端點,獲取服務(wù)的 WSDL 等詳細信息。另外 Call 類用于管理每個服務(wù)請求動作,它可以設(shè)置每個請求的方法,最后通過call.invoke(Object[])調(diào)用服務(wù),并獲取完成后的返回值。

     1     public static void main(String[] args) throws 
     2         RemoteException, MalformedURLException, ServiceException {
     3         HelloWorld();
     4     }
     5 
     6     private static void HelloWorld() throws
     7         ServiceException,RemoteException{
     8         //生成服務(wù)對象Service
     9         Service service=new Service();
    10         Call call=(Call) service.createCall();
    11         //設(shè)置Endpoint地址
    12         call.setTargetEndpointAddress(
    13             "http://localhost:8080/axis.server/services/PersonService");
    14         //綁定請求方法名稱
    15         call.setOperationName("HelloWorld");
    16         //通過call.invoke調(diào)用服務(wù),獲取返回值
    17         String data=(String)call.invoke(new Object[]{"Leslie"});
    18         System.out.println(data);
    19     }

    如果覺得使用 Call 實現(xiàn)請求較為麻煩,Service 中還提供一個 getPort 方法,通過此方法還可直接實現(xiàn)服務(wù)接口 PersonServiceImpl。另外,Axis 還為準(zhǔn)備了一個 ServiceFactory 工廠,通過 ServiceFactory 可以直接獲取 Service 對象。

     1     public static void main(String[] args) throws 
     2         RemoteException, MalformedURLException, ServiceException {
     3         // TODO Auto-generated method stub
     4          HelloWorld();
     5     }
     6 
     7     private static void HelloWorld() throws 
     8         ServiceException, RemoteException, MalformedURLException {
     9         String wsdl="http://localhost:8080/axis.server/services/PersonService?wsdl";
    10         String uri="http://localhost:8080/axis.server/services/PersonService";
    11         String serviceName="PersonServiceImplService";
    12         
    13         //使用serviceFacotry直接生成服務(wù)
    14         ServiceFactory factory=ServiceFactory.newInstance();
    15         Service service=(Service) factory.createService(
    16                 new URL(wsdl),new QName(uri,serviceName));
    17         
    18         //使用service.getPort方法實現(xiàn)服務(wù)接口
    19         PersonServiceImpl personService=(PersonServiceImpl)service
    20                 .getPort(PersonServiceImpl.class);
    21         String data=personService.helloWorld("Leslie");
    22         System.out.println(data);
    23     }

     

    2.3 以自定義對象傳輸數(shù)據(jù)

    若需要以自定義對象作為數(shù)據(jù)傳輸?shù)妮d體,則需要為自定義對象繼承 Serializable 接口。另外可以留意一下服務(wù)的 wsdl , 因為 Axis 并沒有默認使用List , Map 等類型, 在 List,Map 等作為參數(shù)時,wsdl 都會把返回類型設(shè)置為 ArrayOf_xsd_anyType,所以建議使用簡單數(shù)組作為返回值。

     1 public class PersonEntity implements Serializable {
     2      private Integer id;
     3      private String name;
     4      private Integer age;
     5      private String address;
     6      
     7      public PersonEntity(Integer id,String name,Integer age,String address){
     8          this.id=id;
     9          this.name=name;
    10          this.age=age;
    11          this.address=address;
    12      }
    13      
    14      public Integer getId(){
    15          return id;
    16      }
    17      
    18      public void setId(Integer id){
    19          this.id=id;
    20      }
    21      ..........
    22  }
    23  
    24  public interface IPersonService {
    25      PersonEntity GetPerson(int id);
    26      PersonEntity[] GetList();
    27      List GetList(String name);
    28  }
    29  
    30  public class PersonServiceImpl implements IPersonService {
    31      @Override
    32      public PersonEntity[] GetList(){
    33          PersonEntity[] list=new PersonEntity[2];
    34          PersonEntity person1=new PersonEntity(1,"Leslie",32,"tianhe");
    35          PersonEntity person2=new PersonEntity(2,"Elva",31,"henan");
    36          list[0]=person1;
    37          list[1]=person2;
    38          return list;
    39      }
    40      
    41      @Override
    42      public List GetList(String name){
    43          List list=new ArrayList();
    44          PersonEntity person1=new PersonEntity(1,name+" Lee",32,"tianhe");
    45          PersonEntity person2=new PersonEntity(2,name+" Chen",31,"henan");
    46          list.add(person1);
    47          list.add(person2);
    48          return list;
    49      }
    50      
    51      @Override
    52      public PersonEntity GetPerson(int id){
    53          return new PersonEntity(id,"Leslie",32,"tianhe");
    54      }
    55  }

    在 server-config.wsdd 中使用 beanMapping 加入自定義對象綁定,以 languageSpecificType 綁定類名,qname 可由用戶設(shè)置,但必須與 xmln 特性相對應(yīng)。

    1   .........
    2    <service name="PersonService" provider="java:RPC">
    3        <parameter name="className"  value="axis.serviceImpls.PersonServiceImpl" />
    4        <parameter name="allowedMethods" value="*" />
    5        <parameter name="scope"  value="application" />
    6        <beanMapping qname="myNS:PersonEntity" xmlns:myNS="urn:PersonEntity" 
    7            languageSpecificType="java:axis.entity.PersonEntity" />
    8    </service>
    9    .........

    以 WSDL2Java 生成客戶端代碼后,可以留意 PersonEntity 對象已經(jīng)自動實現(xiàn)了 Serializable 接口,增加了 getDeserializer、getSerializer 等序列化與反序列化方法。此時直接使用代理類,會自動地完成對象序列化的過程,可以節(jié)省了不少時間。

     1      public static void main(String[] args) throws 
     2          RemoteException, MalformedURLException, ServiceException {
     3          GetList();
     4          GetPerson();
     5      }     
     6      
     7      private static void GetPerson() throws 
     8          RemoteException, MalformedURLException{
     9          PersonServiceImpl personService=new PersonServiceSoapBindingStub(
    10                  new URL("http://localhost:8080/axis.server/services/PersonService"),
    11                  new PersonServiceImplServiceLocator());
    12          PersonEntity person=personService.getPerson(1);
    13          DisplayPersonProperty(person);
    14      }
    15 
    16      private static void GetList() throws 
    17         ServiceException, RemoteException, MalformedURLException{
    18         PersonServiceImpl personService=new PersonServiceSoapBindingStub(
    19                 new URL("http://localhost:8080/axis.server/services/PersonService"),
    20                 new PersonServiceImplServiceLocator());
    21         Object[] objs=personService.getList("Leslie");
    22         for(Object person:objs)
    23            DisplayPersonProperty((PersonEntity)person);
    24      }
    25 
    26      //顯示對象屬性
    27      private static void DisplayPersonProperty(PersonEntity person){
    28          System.out.println("Id:"+person.getId()+"  Name:"+person.getName()+"  Age:"+
    29              person.getAge()+"  Address:"+person.getAddress());
    30      }

    但需要注意,如果使用 Service 類去調(diào)用服務(wù)的時候,需要使用 Call.registerTypeMapping 注冊一個類型,把接收到的信息轉(zhuǎn)換為 PersonEntity 類型。在注冊類型時 namespaceURI 參數(shù)值需要與服務(wù)端 server-config.wsdd 中的值保持一致。

     1      public static void main(String[] args) throws 
     2          RemoteException, MalformedURLException, ServiceException {
     3          // TODO Auto-generated method stub
     4          GetArray();
     5          GetList();
     6      }    
     7 
     8      private static void GetArray() throws 
     9          ServiceException, RemoteException{
    10          Service service=new Service();
    11          Call call=(Call)service.createCall();
    12          call.setTargetEndpointAddress(
    13               "http://localhost:8080/axis.server/services/PersonService");
    14          
    15          //注冊返回類型,namespaceURI 必須與服務(wù)端注冊值一致
    16          QName qName2=new QName("urn:PersonEntity","PersonEntity");     
    17          call.registerTypeMapping(PersonEntity.class, qName2,
    18                 new BeanSerializerFactory(PersonEntity.class,qName2), 
    19                 new BeanDeserializerFactory(PersonEntity.class,qName2));
    20          
    21          //綁定請求方法
    22          call.setOperation("GetList");
    23          
    24          //設(shè)置返回類型
    25          call.setReturnClass(PersonEntity[].class);
    26          PersonEntity[] list=(PersonEntity[]) call.invoke(new Object[]{});
    27          for(PersonEntity person:list)
    28              DisplayPersonProperty(person);
    29      }
    30     
    31      private static void GetList() throws 
    32         ServiceException, RemoteException{
    33         Service service=new Service();
    34         Call call=(Call)service.createCall();
    35         call.setTargetEndpointAddress(
    36                 "http://localhost:8080/axis.server/services/PersonService");
    37         
    38         //注冊返回類型,namespaceURI 必須與服務(wù)端注冊值一致
    39         QName qName2=new QName("urn:PersonEntity","PersonEntity");     
    40         call.registerTypeMapping(PersonEntity.class, qName2,
    41                new BeanSerializerFactory(PersonEntity.class,qName2), 
    42                new BeanDeserializerFactory(PersonEntity.class,qName2));
    43         
    44         //綁定請求方法
    45         call.setOperationName(new javax.xml.namespace.QName(
    46                 "http://serviceImpls.axis", "GetList"));
    47         //輸入?yún)?shù)
    48         Object[] list=(Object[]) call.invoke(new Object[]{"Leslie"});
    49         for(Object person:list)
    50             DisplayPersonProperty((PersonEntity)person);
    51      }
    52      
    53      private static void DisplayPersonProperty(PersonEntity person){
    54          System.out.println("Id:"+person.getId()+"  Name:"+person.getName()+"  Age:"+
    55              person.getAge()+"  Address:"+person.getAddress());
    56      }

    回到目錄

    三、Web服務(wù)會話管理

    記得在第二節(jié)曾經(jīng)為大家介紹服務(wù)對象的生成方式,當(dāng) scope 設(shè)置 session 時,系統(tǒng)會對同一個客戶代理對象所發(fā)送的請求使用同一個服務(wù)對象,并把服務(wù)信息放在同一個上下文當(dāng)中。利用 session 可以把用戶名、用戶密碼、訂單號此類信息在方法中傳播,也可以確保不同的客戶信息分別保存在不同的上下文之上。session 數(shù)據(jù)的保存時間可以通過 session.setTimeout 方法設(shè)置。

     1 public interface ILoginService {
     2     public Boolean Login(String name,String password);
     3     public String GetUserName();
     4 }
     5 
     6 public class LoginServiceImpl implements ILoginService {
     7 
     8     @Override
     9     public Boolean Login(String name, String password) {
    10         // TODO Auto-generated method stub
    11         MessageContext context=MessageContext.getCurrentContext();
    12         Session session=context.getSession();
    13         if(session!=null)
    14             context.getSession().set("User",name);
    15          return true;
    16     }
    17     
    18     @Override
    19     public String GetUserName(){
    20         MessageContext context=MessageContext.getCurrentContext();
    21         Session session=context.getSession();
    22         return session.get("User").toString();
    23     }
    24 }

    在 server-config.wsdd 中,把 scope 設(shè)置為 session 模式

    1    .......
    2    <service name="LoginService" provider="java:RPC" style="wrapped">
    3        <parameter name="className"  value="axis.serviceImpls.LoginServiceImpl" />
    4        <parameter name="allowedMethods" value="*" />
    5        <parameter name="scope"  value="session" />
    6    </service>
    7    .......

    在客戶端調(diào)用時,需要把 maintainSession 設(shè)置為 true,此時可以把 userName , password 等信息存到上下文當(dāng)中。

     1     public static void main(String[] args) throws 
     2         RemoteException, MalformedURLException, ServiceException {
     3         // TODO Auto-generated method stub
     4         Login();
     5     }
     6     
     7     private static void Login() throws 
     8         MalformedURLException, RemoteException{
     9         LoginServiceImpl service1=getService();
    10         LoginServiceImpl service2=getService();
    11         
    12         service1.login("Leslie", "12345678");
    13         service2.login("Jack", "12345678");
    14         
    15         System.out.println("UserName: "+service1.getUserName());
    16         System.out.println("UserName: "+service2.getUserName());
    17     }
    18     
    19     private static LoginServiceImpl getService() throws
    20         AxisFault, MalformedURLException{
    21         LoginServiceImplServiceLocator locator=new LoginServiceImplServiceLocator();
    22         locator.setMaintainSession(true);
    23         LoginServiceImpl loginService=new LoginServiceSoapBindingStub(
    24                 new URL("http://localhost:8080/axis.server/services/LoginService"),
    25                 locator);      
    26         return loginService;
    27     }

    測試結(jié)果


    回到目錄 

    四、自定義 Handler

    Axis 的 Handler 與 Servlet 中的 Filter 有點相似,用于過濾服務(wù),檢測管理 Web 服務(wù)信息的接收發(fā)送過程。開發(fā) Handler 需要實現(xiàn) org.apache.axis.Handler 接口,接口包含了下面多個方法:


    為了簡化 Handler 的開發(fā),Axis 在org.apache.axis.handlers 命名空間內(nèi)就為客戶提供了 BasicHandler、ErrorHandler、LogHandler、SimpleSessionHandler、SimpleAuthenticationHandler、SimpleAuthorizationHandler 等 Handler 用于管理 Axis 的錯誤處理,日志記錄,身份認證,權(quán)限管理等工作。BasicHandler 是實現(xiàn) Handler 接口的基礎(chǔ)類,用戶可以繼承 BasicHandler 類, 開發(fā)自定義的 Handler 對特定的服務(wù)分別在服務(wù)請求request 、信息回送 response 時進行處理。init、invoke 是 BasicHandler 最常用的方法, init 方法會在對象初始化時執(zhí)行,而對服務(wù)的管理操作可以在 invoke 方法中定義。invoke 方法包括了 messageContext 參數(shù) , 利用 messageContext ,可以獲取到服務(wù)的 SOAP ,HttpServletRequest 、HttpServletResponse、URL 等相關(guān)信息。
    下面的例子就是利用自定義的 LoginHandler 對 LoginService 服務(wù)請求進行監(jiān)聽。
    首先修改 server-config.wsdd 文件,在 LoginService 服務(wù)的 requestFlow 中加入 LoginHandler 。

     1    .......
     2    <service name="LoginService" provider="java:RPC" style="wrapped">
     3        <parameter name="className"  value="axis.serviceImpls.LoginServiceImpl" />
     4        <parameter name="allowedMethods" value="*" />
     5        <parameter name="scope"  value="session" />
     6        <requestFlow>
     7            <handler type="java:axis.handler.LoginHandler"/>
     8        </requestFlow>
     9    </service>
    10    ......

    建立 LoginService,在對 LoginService 服務(wù)接收到 SOAP 請求時,系統(tǒng)可以通過 LoginHandler 監(jiān)聽請求信息,獲取相關(guān)的方法名,輸入?yún)?shù)等信息。通過 messageContext.getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST) 方法,可以獲取到 HttpServletRequest 對象。

     1 public interface ILoginService {
     2      public Boolean Login(String name,String password);
     3  }
     4  
     5  public class LoginServiceImpl implements ILoginService {
     6  
     7      @Override
     8      public Boolean Login(String name, String password) {
     9          // TODO Auto-generated method stub
    10          UserService service=new UserService();
    11          User user=service.getUser(name);
    12          if(user!=null)
    13              return user.password==password;
    14          else
    15              return false;
    16      }
    17  }
    18  
    19  public class LoginHandler extends BasicHandler{
    20      private MessageContext context;
    21      
    22      public void invoke(MessageContext context){
    23          this.context=context;
    24          GetServletRequest();
    25          GetSOAP();
    26      }
    27      
    28      //獲取HtppServletRequest對象
    29      private void GetServletRequest(){
    30          HttpServletRequest request = (HttpServletRequest)context
    31                  .getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST);
    32          String remoteAddress=request.getRemoteAddr();
    33          String method=request.getMethod();
    34          StringBuffer URL=request.getRequestURL();
    35          String message=String.format("Client Address:%s\nMethod:%s\n" +
    36                  "RequestURL:%s\n", remoteAddress,method,URL);
    37          System.out.println(message);
    38      }
    39      
    40      //獲取SOAPBody信息
    41      private void GetSOAP(){
    42          String soap=null;
    43          try {
    44              soap=context.getCurrentMessage().getSOAPBody().toString();
    45          } catch (SOAPException e) {
    46              // TODO Auto-generated catch block
    47              e.printStackTrace();
    48          }
    49          if(soap!=null){
    50              String[] data= soap.split(">");
    51              for(String line:data)
    52                 System.out.println(line+">");
    53          }
    54      }
    55  }

    客戶端

     1     public static void main(String[] args) throws 
     2          RemoteException, MalformedURLException, ServiceException {
     3          LoginServiceImpl service1=getService();
     4          service1.login("Leslie", "12345678");  
     5      }
     6 
     7      private static LoginServiceImpl getService() throws
     8          AxisFault, MalformedURLException{
     9          LoginServiceImplServiceLocator locator=new LoginServiceImplServiceLocator();
    10          locator.setMaintainSession(true);
    11          LoginServiceImpl loginService=new LoginServiceSoapBindingStub(
    12                  new URL("http://localhost:8080/axis.server/services/LoginService"),
    13                  locator);      
    14          return loginService;
    15      }

    只要在 service 的 requestFlow 對 Handler 進行綁定,在客戶端發(fā)送請求后, Handler 就能對服務(wù)請求進行監(jiān)聽。


     

    同樣地,在 service 的 responseFlow 輸入流中對 Handler 進行綁定,就可以對回發(fā)的 SOAP 信息進行監(jiān)聽。
    下面例子是利用自定義 LoginHandler 對用戶的登錄回發(fā)信息進行監(jiān)察,計算成功登錄的在線人數(shù) 。
    首先修改 server-config.wsdd 文件,在 LoginService 服務(wù)的 responseFlow 中加入 LoginHandler 。

    1    <service name="LoginService" provider="java:RPC" style="wrapped">
    2        <parameter name="className"  value="axis.serviceImpls.LoginServiceImpl" />
    3        <parameter name="allowedMethods" value="*" />
    4        <parameter name="scope"  value="session" />
    5        <responseFlow>
    6            <handler type="java:axis.handler.LoginHandler"/>
    7        </responseFlow>
    8    </service>

    在自定義 Handler 中可以通過 Message.getSOAPEnvelope , Message.getSOAPHead ,Message.getSOAPBody 等多個方法對 Web 服務(wù)的回發(fā)信息進行監(jiān)測。若登錄成功,系統(tǒng)檢測到 LoginReturn 值為 true 時,則修改成功登錄人數(shù)數(shù)量。
    除此以外,開發(fā)人員還可在 SOAP 的 head、body 等多處地方額外添加回發(fā)信息。下面的例子將記錄成功登陸的人數(shù),并把此信息記錄在頭文件中返還到客戶端。

     1   public interface ILoginService {
     2          public Boolean login(String name,String password);
     3   }
     4   
     5   public class LoginServiceImpl implements ILoginService {
     6   
     7       @Override
     8       public Boolean login(String name, String password) {
     9           UserService userService=new UserService();
    10           User user=userSerivice.getUser(name);
    11           if(user!=null)
    12             return user.password==password;
    13           else
    14             return false;
    15       }
    16   }
    17   
    18  public class LoginHandler extends BasicHandler{
    19      private MessageContext context;
    20      
    21      public void invoke(MessageContext context){
    22          this.context=context;
    23          try {
    24              if(success())
    25                 logged();
    26              addElement();
    27              getSOAP();
    28          } catch (AxisFault e) {
    29              e.printStackTrace();
    30          } catch (SOAPException e) {
    31              e.printStackTrace();
    32          }
    33      }
    34      
    35      //記錄登錄人數(shù) 
    36      private void logged(){
    37          Handler handler=context.getService();
    38          //判斷服務(wù)是否為LoginService
    39          if(handler.getName().equals("LoginService")){
    40              if(this.getOption("loggedCount")==null)
    41                  this.setOption("loggedCount", 0);
    42  
    43              Integer count=Integer.parseInt(
    44                      this.getOption("loggedCount").toString());
    45              count++;
    46              this.setOption("loggedCount", count);
    47  
    48              System.out.println("logged count: "+count+"   "+
    49                 new Date().toString()+"\n");
    50          }
    51      }
    52      
    53      //獲取LoginService服務(wù)返回值
    54      //若登錄成功則返回true,失敗則返回false
    55      private Boolean success() throws SOAPException{
    56          SOAPBody soap=context.getCurrentMessage().getSOAPBody();
    57          Node node=soap.getElementsByTagName("LoginReturn").item(0);
    58          return node.toString().contains("true");
    59      }
    60      
    61      //在回發(fā)的SOAP中加入已登錄人數(shù)的信息
    62      private void addElement() throws SOAPException  {
    63          SOAPEnvelope soap=context.getCurrentMessage().getSOAPEnvelope();
    64          SOAPElement element=soap.getHeader().addChildElement("loggedOnline");
    65          element.addTextNode(this.getOption("loggedCount").toString());
    66      }
    67      
    68      //顯示SOAP信息
    69      private void getSOAP() throws AxisFault{
    70          SOAPEnvelope soap=context.getCurrentMessage().getSOAPEnvelope();
    71          if(soap!=null){
    72              String[] data= soap.toString().split(">");
    73              for(String line:data)
    74                 System.out.println(line+">");
    75          }
    76      }
    77  }

    客戶端

     1     public static void main(String[] args) throws 
     2          RemoteException, MalformedURLException, ServiceException {
     3          LoginServiceImpl service1=getService();
     4          service1.login("Leslie", "12345678");  
     5      }
     6 
     7      private static LoginServiceImpl getService() throws
     8          AxisFault, MalformedURLException{
     9          LoginServiceImplServiceLocator locator=new LoginServiceImplServiceLocator();
    10          locator.setMaintainSession(true);
    11          LoginServiceImpl loginService=new LoginServiceSoapBindingStub(
    12                  new URL("http://localhost:8080/axis.server/services/LoginService"),
    13                  locator);      
    14          return loginService;
    15      }

    運行結(jié)果


     

     回到目錄

    五、新一代 SOAP 引擎 Axis 2.x

    5.1 Axis 2.x 核心結(jié)構(gòu)

    Axis 1.x 建立在 JAX-RPC 基礎(chǔ)之上的, 但事實證明這并非一個好方法,因為 JAX-RPC 限制了 Axis 代碼的功能,而且造成了性能問題使系統(tǒng)缺乏靈活性。Axis 2.x 在設(shè)計時已經(jīng)考慮到靈活性操作的問題,它同時實現(xiàn)了對 JAXB 2.x、 Java XML 數(shù)據(jù)綁定標(biāo)準(zhǔn),并以 JAX-WS 技術(shù)替代了 JAVA-PRC 作為 Java Web 服務(wù)標(biāo)準(zhǔn)。
    Axis 2.x 是純 SOAP 處理引擎,它的核心功能是處理傳輸消息,并將其交付給目標(biāo)應(yīng)用程序。像 JAX-WS 此類 Web 服務(wù)標(biāo)準(zhǔn)不會進入 Axis 2.x 核心部分當(dāng)中,而只作為 Axis 2.x 服務(wù)傳遞組件。 AXIOM(Axis2 Object Model,Axis 2 對象模型)才是 Axis2 的基礎(chǔ),任何 SOAP 消息在 Axis2 中都可看作為 AXIOM。它把延遲構(gòu)建和輕型的可定制對象模型結(jié)合了起來,盡可能地減輕對系統(tǒng)資源特別是 CPU 和內(nèi)存的壓力。
    關(guān)于 Axis 2.x 的消息處理過程與 AXIOM 對象模型將在下節(jié)再作進一步介紹。

     

    5.2 Axis 2.x 安裝部署
    Axis 2.x 可以在 http://axis.apache.org/axis2/java/core/index.html 下載,當(dāng)中包括Binary Distribution、WAR 等多個版本,使用WAR 版本更方便把 Web 服務(wù)部署到 Tomcat、WebLogic 等服務(wù)管理器上,在開發(fā)階段,使用 Binary Dirstribution 等版本更便于服務(wù)的調(diào)試。
    完成下載后在環(huán)境變量中把 Axis2_Home 綁定到 Axis 2.x 的根目錄,在 path 加入設(shè)置  ".;%Axis2_Home%\bin "。
    Axis 1.x 當(dāng)中只是包括了幾個工具包,而 Axis 2.x 更像是一個框架,在 Axis 2.x 項目的“\WebRoot\WEB-INF\” 文件夾內(nèi)包含了 Axis 2.x 多個儲存庫,在 “ conf ” 文件夾內(nèi)的 “ axis2.xml ” 文件是 Axis 2.x 全局描述符,所有的系統(tǒng)級配置都是通過 “ axis2.xml ” 文件完成的。在 “ services” 文件夾是用于存放后綴名為 “ *.aar ” 的服務(wù)模塊的,在 “ modules ” 文件夾內(nèi)用于存放后綴名為 “ *.mar ” 的自定義模塊的,在 “ pojo ” 文件夾內(nèi)用于存放傳統(tǒng)的 POJO 對象服務(wù)文件。 而服務(wù)描述符 “services.xml” 文件 與模塊描述符 “module.xml”文件則存放于“ \WebRoot\META-INF ” 文件夾當(dāng)中。

     

    5.3 將傳統(tǒng)的 POJO 對象作為服務(wù)對象部署

    Axis 2.x 為用戶提供了最簡約的服務(wù)部署方式,能把簡單的一個 POJO 對象作為服務(wù)發(fā)布。
    首先在一個缺省包里建立一個 POJO 對象,再把被編譯后的 Example.class 文件加入到 “\WebRoot\WEB-INF\pojo\” 文件夾內(nèi),此時 Example 即會被默認為POJO 服務(wù)。

    1 public class Example {
    2     public String HelloWorld(String name){
    3         return "Hello "+name;
    4     }
    5 }

    運行程序后,你就可以 http://leslie-laptop:8080/axis2-1.6.2/services/Example?wsdl 上看到 Example 服務(wù)的 wsdl 信息。

     

    5.4 以存檔文件部署服務(wù)

    使用 POJO 對象部署服務(wù)固然簡單,但由于在安全性事務(wù)、消息監(jiān)聽等方面缺乏支持,所以 Axis 2.x 更多時候是使用存檔文件方式部署服務(wù)的。首先在項目內(nèi)建立服務(wù)接口 PersonService 和 服務(wù)類PersonServiceImpl。

     1 public class PersonEntity implements Serializable {
     2     private Integer id;
     3     private String name;
     4     private Integer age;
     5     private String address;
     6     
     7     public PersonEntity(Integer id,String name,Integer age,String address){
     8         this.id=id;
     9         this.name=name;
    10         this.age=age;
    11         this.address=address;
    12     }
    13     
    14     public Integer getId(){
    15         return id;
    16     }
    17     
    18     public void setId(Integer id){
    19         this.id=id;
    20     }
    21     ........
    22 }
    23 
    24 public interface PersonService {
    25     PersonEntity getPerson(int id);
    26     PersonEntity[] getList();
    27     List<PersonEntity> getListByName(String name);
    28 }
    29 
    30 public class PersonServiceImpl implements PersonService {
    31 
    32     @Override
    33     public PersonEntity[] getList(){
    34         PersonEntity[] list=new PersonEntity[2];
    35         PersonEntity person1=new PersonEntity(1,"Leslie",32,"tianhe");
    36         PersonEntity person2=new PersonEntity(2,"Elva",31,"henan");
    37         list[0]=person1;
    38         list[1]=person2;
    39         return list;
    40     }
    41     
    42     @Override
    43     public List<PersonEntity> getListByName(String name){
    44         List<PersonEntity> list=new LinkedList<PersonEntity>();
    45         PersonEntity person1=new PersonEntity(1,name+" Lee",32,"tianhe");
    46         PersonEntity person2=new PersonEntity(2,name+" Chen",31,"henan");
    47         list.add(person1);
    48         list.add(person2);
    49         return list;
    50     }
    51     
    52     @Override
    53     public PersonEntity getPerson(int id){
    54         return new PersonEntity(id,"Leslie",32,"tianhe");
    55     }
    56 }

    在 “ \WebRoot\META-INF ” 文件夾內(nèi)加入配置文件 services.xml 。當(dāng)中 ServiceClass 的 parameter 用于綁定服務(wù)實現(xiàn)類,而 operation 用于綁定要暴露的服務(wù)方法。
    Axis 2.x 支持三種信息交換模式,包括 In-Only,Robust-In,In-Out 。In-Only 消息交換模式只接收 SOAP 請求,而無需返還信息;Robust-In 消息交換模式發(fā)送SOAP 請求,只有在出錯的情況下才返回應(yīng)答;  In-Out 消息交換模式總是對 SOAP 請求返還信息。在服務(wù)的 messageReceive 設(shè)置中有 RPCMessageReceiver、RawXMLINOutMessageReceiver、RawXMLINOnlyMessageReceiver 等多個選項可以針對不同 Web 服務(wù)方法設(shè)置不同的信息交換模式。

     1  <service name="PersonService">  
     2    <description>This is a sample Web Service.</description>
     3    <!--ServiceClass指定實現(xiàn)服務(wù)的類。   -->  
     4    <parameter name="ServiceClass" locked="false">
     5        axis2.serviceImpl.PersonServiceImpl
     6    </parameter>  
     7    <!-- operation 與Java Class中方法名對應(yīng)。 -->  
     8    <operation name="getPerson">  
     9       <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>  
    10    </operation>
    11    <operation name="getList">  
    12       <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>  
    13    </operation> 
    14    <operation name="getListByName">  
    15       <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>  
    16    </operation> 
    17 </service> 

    完成配置后,把 “META-INF\services.xml ” 文件(包含文件夾 META-INF)和服務(wù)類 PersonEntity.class、PersonService.class、PersonServiceImpl 復(fù)制到自定義文件夾 “axis2serivces” 當(dāng)中。打開命令提示符,進入 axix2services 文件夾輸入命令 “ jar  cvf  axisService.aar  . ” (注意:“.” 代表生成包含文件夾所有文件)。最后把 “ axisService.aar ” 文件加入到 “\WebRoot\WEB-INF\services” 文件夾當(dāng)中,啟動 Axis2.x 項目,打開 http://leslie-laptop:8080/axis2-1.6.2/services/PersonService?wsdl 就可看到 PersonService 服務(wù)的 wsdl 信息。在 wsdl 中可以看到 axis2 支持 SOAP 1.1、 SOAP 1.2 等多種傳輸格式。


    Axis 2.x 支持多種客戶端生成工具,包括原有 WSDL2Java 工具
    WSDL2Java -uri http://localhost/axis2-1.6.2/services/PersonSerivce.wsdl -p 包名 -o 文件夾
    還有支持 JAX-WS 的 WsImport 工具
    Wsimport  -p  包名  -keep -extension  http://localhost/axis2-1.6.2/services/PersonSerivce.wsdl
    也可使用 MyEclipse 自帶的 JAX-WS 客戶端生成工具完成。
    生成客戶端后可以進行測試

     1     public static void main(String[] args) throws  MalformedURLException {
     2         // TODO Auto-generated method stub
     3         getList();
     4     }
     5     
     6     private static void getList() throws MalformedURLException{
     7          PersonService personService=new PersonService();
     8          PersonServicePortType personServicePortType=personService
     9                  .getPersonServiceHttpSoap12Endpoint();
    10          List<PersonEntity> personList=personServicePortType.getList();
    11          for(PersonEntity person:personList)
    12              displayPersonProperty(person);
    13     }
    14 
    15     private static void displayPersonProperty(PersonEntity person){
    16         System.out.println("Id:"+person.getId().getValue()+"  Name:"
    17            +person.getName().getValue()+"  Age:"+ person.getAge().getValue()
    18            +"  Address:"+person.getAddress().getValue());
    19     }

    測試結(jié)果


     回到目錄

    六、AXIOM 對象模型

    6.1 AXIOM 的特點

    AXIOM(Axis Object Model, Axis 對象模型)是 Axis 2.x 對 XML 信息處理的核心部分,它把延遲構(gòu)建和可定制對象模型技術(shù)結(jié)合起來,極大地提高了 SOAP 信息構(gòu)建的靈活度。對應(yīng) Axis 1.x 的 SAX ( Simple API for XML)推式(Push)解析器,Axis 2.x 使用更具靈活性的 StAX(Streaming API for XML ) 拉式(Pull)解析器,可盡量減輕對系統(tǒng)資源的壓力。在使用推方式(Push)的情況下,系統(tǒng)會先定義數(shù)據(jù)的處理程序,然后在數(shù)據(jù)錄入時對處理程序進行回調(diào)。然而回調(diào)操作只能對錄入的數(shù)據(jù)進行如讀取、修改等某些操作,除非引發(fā)異常,否則無法左右 XML 文檔的錄入。而 AXIOM 所使用的拉式(Pull)解析器,實際上是一個高效的迭代器,它使用 XML 樹形結(jié)構(gòu)方式,支持延時構(gòu)建,可以根據(jù)需要對文檔中的不同部分進行遍歷。在大型的 XML 文件中,使用拉式解析器更具吸引力,它可以僅對部分 XML 數(shù)據(jù)進行處理,剩下的留給解析器完成操作。
    在 Web服務(wù)開發(fā)過程中,大部分的開發(fā)人員都是以對象的形式進行信息傳遞,并使用 WSDL2Java 等工具構(gòu)建服務(wù)代理以實現(xiàn) XML 數(shù)據(jù)與對象之間的轉(zhuǎn)換。然而使用此方式限制了Web 服務(wù)框架中的數(shù)據(jù)綁定的靈活程度,利用 AXIOM 的特性更便于 XML 與 Java 對象之間轉(zhuǎn)換,大部分的 JAVA 對象都可以利用 AXIOM 轉(zhuǎn)換成 SOAP 信息。

     

    6.2 AXIOM 的使用方式

    AXIOM 建立于 StAX 拉式解析器的基礎(chǔ)上,它為開發(fā)人員準(zhǔn)備了完善的 API ,其中最常用到的是 OMFactory 工廠,它提供了createOMNamespace、createOMElement、createOMAttribute、createOMDocument、createOMText 等多個方法用于建立 XML 文檔信息。在 BeanUtil 類中還包括了 getPullParser、getOMElement、processObject 等多個靜態(tài)方法用于處理自定義對象與XML之間的轉(zhuǎn)換。
    下面以POCO服務(wù)作為一個例子,演示一下 AXIOM 對象綁定方式。在客戶端 Web服務(wù)分為 SOAP 請求數(shù)據(jù)綁定與返回信息處理兩個階段,在服務(wù)請求階段系統(tǒng)會把設(shè)定的服務(wù)地址、傳輸方式綁定到 ServiceClient 請求對象當(dāng)中,然后利用 serviceClient.sendReceive 的方法把已定義的 OMElement 對象信息加入到 SOAP 當(dāng)中發(fā)送到服務(wù)端。當(dāng)接收到返回信息后,再把 OMElement 信息轉(zhuǎn)換為對象顯示。

     1      public static void main(String[] args) throws AxisFault {
     2          excute();
     3      }
     4  
     5      public static void excute() throws AxisFault{
     6          //設(shè)置 endpoint 地址
     7          EndpointReference targetEndpoint=new EndpointReference(
     8          "http://leslie-laptop:8080/axis2-1.6.2/services/PersonService"); 
     9          Options options=new Options();   
    10          options.setTo(targetEndpoint); 
    11          
    12          //設(shè)置傳輸方式
    13          //可使用 TRANSPORT_JMS;TRANSPORT_HTTP;TRANSPORT_MAIL;TRANSPORT_TCP;
    14          options.setTransportInProtocol(Constants.TRANSPORT_HTTP);   
    15          
    16          //把設(shè)置的地址、傳輸方式綁定到Service請求當(dāng)中
    17          ServiceClient sender=new ServiceClient();   
    18          sender.setOptions(options);   
    19          
    20          //設(shè)置請求的 SOAP 信息
    21          OMElement requestOMElement=getPersonRequest(1);   
    22          OMElement responseOMElement=sender.sendReceive(requestOMElement);   
    23          
    24          //對返回的SOAP進行處理,顯示返回值
    25          PersonEntity person=convertToPerson(responseOMElement);
    26          displayPersonProperty(person);
    27      }
    28      
    29      private static OMElement getPersonRequest(Integer id){
    30          //新建OMFactory工廠
    31          OMFactory factory=OMAbstractFactory.getOMFactory();   
    32          
    33          //加入OMNamespace、OMElement、OMText 等數(shù)據(jù)
    34          OMNamespace omNs=factory.createOMNamespace(
    35                 "http://ws.apache.org/axis2","myNS");     
    36          OMElement value=factory.createOMElement("id",omNs);   
    37          value.addChild(factory.createOMText(value,id.toString()));  
    38          
    39          //加入請求方法名
    40          OMElement method=factory.createOMElement("getPerson",omNs); 
    41          method.addChild(value);  
    42          return method;  
    43      }
    44      
    45      //把返回OMElement對象轉(zhuǎn)換成 person對象 
    46      private static PersonEntity convertToPerson(OMElement element) 
    47              throws AxisFault{
    48          PersonEntity person =null;
    49          OMElement omElement = element.getFirstElement().getFirstElement();
    50          String localName=omElement.getLocalName().toLowerCase();
    51          if (localName.equals("personentity")) {
    52             person = (PersonEntity) BeanUtil.processObject(omElement,
    53             PersonEntity.class, null, true, new DefaultObjectSupplier(), null);      
    54          }
    55          return person;
    56      }
    57      
    58      private static void displayPersonProperty(PersonEntity person){
    59          System.out.println("Id:"+person.getId()+"  Name:"+person.getName()
    60             +"  Age:"+ person.getAge() +"  Address:"+person.getAddress());
    61      }

    發(fā)送的 SOAP 請求


    在服務(wù)端,系統(tǒng)會從發(fā)送的SOAP信息中獲取請求的 id 值,并通過 BeanUtil.getPullParser 等方法把 personEntity 對象轉(zhuǎn)換成 SOAP 信息返還到客戶端。

     1 public class PersonService {
     2 
     3     public OMElement getPerson(OMElement element){
     4         //獲取請求條件 Id
     5         Integer id=Integer.valueOf(element.getText());
     6         //模擬返回數(shù)據(jù)
     7         PersonEntity person=new PersonEntity(id,"Leslie",32,"tianhe");
     8         //把person對象轉(zhuǎn)換為OMElement
     9         javax.xml.stream.XMLStreamReader reader=BeanUtil.getPullParser(person);
    10         StreamWrapper parser=new StreamWrapper(reader);
    11         OMXMLParserWrapper stAXOMBuilder=OMXMLBuilderFactory
    12                 .createStAXOMBuilder(OMAbstractFactory.getOMFactory(), parser);
    13         return stAXOMBuilder.getDocumentElement();
    14     }
    15 }

    返還的 SOAP 信息


     

    6.3 突顯 AXIOM 的優(yōu)勢

    在面向?qū)ο蟮?Web服務(wù)開發(fā)模式下,系統(tǒng)都會利用集成工具進行XML信息與對象的自動化轉(zhuǎn)換。數(shù)據(jù)的搜索與查找都會在JAVA對象中進行,在信息交換密度頻繁的系統(tǒng)當(dāng)中,這將占用大量內(nèi)存空間,對系統(tǒng)造成壓力。所以,在返回信息中直接對 XML 數(shù)據(jù)進行攔截、分類、篩選是常用的方法。Axis 2.x 使用更具靈活性的 StAX 拉式解析器,它可以使用虛擬文檔的方式構(gòu)建 XML 樹。每個節(jié)點都可被視為一個容器 OMContainer,它可以使用 OMContainer.getChildren 方法獲取子節(jié)點,再以 Iterator 迭代器的方式對節(jié)點進行遍歷。此外系統(tǒng)還提供了 OMNode.getNextOMSibling、OMNode.getPreviousOMSibling 等多個方法,以進行節(jié)點之間的跳轉(zhuǎn)。這意味著它可以跳過其他的子節(jié)點,直接找到需要的節(jié)點再進行遍歷。在數(shù)據(jù)量較大的系統(tǒng)當(dāng)中使用此種遍歷方式更能突顯出 StAX 拉式(Pull)解析器的優(yōu)勢。
    以下的例子主要為了展示使用 StAX 拉式解析器進行遍歷的方式,BookService 服務(wù)主要是根據(jù)客戶所輸入的出版社信息進行查找,然后把該出版社的書本進行按類分配,返還到客戶端。
    下面是服務(wù)端的代碼:

      1 public class BookEntity {
      2     private Integer id;
      3     private String title;
      4     private String author;
      5     private String publishing;
      6     private String introduction;
      7     private String type;
      8 
      9     public BookEntity(Integer id,String title,String author
     10           ,String type,String publishing,String introduction){
     11        this.id=id;
     12        this.title=title;
     13        this.author=author;
     14        this.type=type;
     15        this.publishing=publishing;
     16        this.introduction=introduction;
     17     }
     18     
     19     public Integer getId(){
     20         return id;
     21     }
     22     
     23     public void setId(Integer id){
     24         this.id=id;
     25     }
     26     ........
     27 }
     28 
     29 public interface BookService {
     30    OMElement getList(OMElement element);
     31 }
     32 
     33 public class BookServiceImpl implements BookService{
     34 
     35     @Override
     36     public OMElement getList(OMElement element) {
     37         //獲取請求信息 publishing 出版社名稱
     38         OMElement child=(OMElement)element.getChildren().next();
     39         String publishing=child.getText();
     40         
     41         // 構(gòu)建 OMFactory 工廠
     42         OMFactory factory=OMAbstractFactory.getOMFactory(); 
     43         OMNamespace omNamespace=factory.createOMNamespace(
     44                 "http://serviceImpl.axis2","ns");   
     45         
     46         //獲取計算機類書本子節(jié)computerElement
     47         List<BookEntity> computerTypeList=getBooks(
     48                 publishing,"computer");
     49         OMElement computerElement=convertToOMElement(
     50                 computerTypeList,"computer",omNamespace);
     51         
     52         //獲取文學(xué)類書本子節(jié)literatureElement
     53         List<BookEntity> literatureTypeList=getBooks(
     54                 publishing,"literature");
     55         OMElement literatureElement=convertToOMElement(
     56                 literatureTypeList,"literature",omNamespace);
     57         //加入多個類型的書本
     58         ...........
     59         //構(gòu)建XML樹
     60         OMElement response=factory.createOMElement(
     61                 "getListResponse",omNamespace); 
     62         OMElement returnValue=factory.createOMElement
     63                 ("return",omNamespace);
     64         OMElement books=factory.createOMElement(
     65                 "publishing",omNamespace);
     66         
     67         books.addAttribute("name", publishing, omNamespace);
     68         books.addChild(computerElement);
     69         books.addChild(literatureElement);
     70         .........
     71         returnValue.addChild(books);
     72         response.addChild(returnValue);
     73         return response;
     74     }
     75 
     76     //把計算機類書本對象轉(zhuǎn)換為XML信息    
     77     private OMElement convertToOMElement(List<BookEntity> list
     78             ,String typeName,OMNamespace omNamespace){    
     79         OMElement omElement=BeanUtil.getOMElement(new QName("theme")
     80           ,list.toArray(),new QName("book"),false,null);
     81         omElement.addAttribute("name",typeName,omNamespace);
     82         return omElement;
     83     }
     84     
     85     //根據(jù)書本類型查找數(shù)據(jù)
     86     private List<BookEntity> getBooks(String publishing,String type){
     87         List<BookEntity> list=new ArrayList<BookEntity>();
     88         for(BookEntity book:virtualDatabase(publishing))
     89             if(book.getType()=="computer")
     90                 list.add(book);
     91         return list;
     92     }
     93     
     94     //虛擬數(shù)據(jù)
     95     private List<BookEntity> virtualDatabase(String publishing){
     96         List<BookEntity> list=new ArrayList<BookEntity>();
     97         BookEntity book1=new BookEntity(
     98             1,"Core JAVA Advanced Features","Gary Cornell",
     99             "computer",publishing,
    100             "Core Java by Cay S. Horstmann and Gary Cornell is a book\n"+
    101             "in the Java series of Sun Microsystems Press, published \n"+
    102             "by Prentice-Hall. The book is aimed at experienced \n"+
    103             "programmers who want to learn how to write useful Java \n" +
    104             "applications and applets. No hype, no toy code, no language \n"+
    105             "lawyering, just solid facts and in-depth research to help you \n"+
    106             "write real programs."
    107         );
    108         list.add(book1);
    109         ........
    110         return list;
    111     }
    112 }

    在配置services.xml文件時,需要把 messageReceiver 設(shè)置為 org.apache.axis2.receivers.RawXMLINOutMessageReceiver

    1  <service name="BookService">  
    2    <description>This is a sample Web Service.</description>  
    3    <!--ServiceClass指定實現(xiàn)服務(wù)的類。   -->
    4    <parameter name="ServiceClass" locked="false">axis2.serviceImpl.BookServiceImpl</parameter>  
    5    <!-- operation 與Java Class中方法名對應(yīng)。 -->  
    6    <operation name="getList">  
    7       <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>  
    8    </operation>
    9  </service>   

    返還的 SOAP 信息


    在客戶端利用 StAX 就可以輕松地對返還數(shù)據(jù)進行分類處理,例如要在返回數(shù)據(jù)當(dāng)中顯示計算機類型的Book信息,可以使用 Iterator 方式進行遍歷,利用 StaX 推時分析的特點跳過其他類型的節(jié)點,直至遇到 ns:name=computer 的節(jié)點時,才把該節(jié)點的XML樹放入容器進行處理。使用此種遍歷方式,所占用的內(nèi)存空間更小,在返回數(shù)據(jù)量較大的系統(tǒng)當(dāng)中更能突顯其優(yōu)勢。

     1     public static void main(String[] args) throws AxisFault {
     2         //設(shè)置請求的endpoint地址
     3         EndpointReference targetEndpoint=new EndpointReference(
     4             "http://leslie-laptop:8080/axis2-1.6.2/services/BookService"); 
     5         Options options=new Options();   
     6         options.setTo(targetEndpoint); 
     7         
     8         //設(shè)置傳輸方式
     9         //可使用 TRANSPORT_JMS;TRANSPORT_HTTP;TRANSPORT_MAIL;TRANSPORT_TCP;
    10         options.setTransportInProtocol(Constants.TRANSPORT_HTTP);   
    11         
    12         //把設(shè)置的地址、傳輸方式綁定到Service請求當(dāng)中
    13         ServiceClient sender=new ServiceClient();   
    14         sender.setOptions(options);   
    15         
    16         //設(shè)置請求的 SOAP 信息,輸入出版社名稱
    17         OMElement requestOMElement=getBookRequest("China Machine Press");  
    18         //發(fā)送請求
    19         OMElement responseOMElement=sender.sendReceive(requestOMElement); 
    20         //遍歷返回值,在返回信息中獲取computer類的Element
    21         OMElement computerBookElement=getComputerElement(responseOMElement);
    22         //把XML轉(zhuǎn)換為BookEntity對象集
    23         List<BookEntity> list=convertToBooks(computerBookElement);
    24         for(BookEntity book:list)
    25             DisplayBook(book);
    26     }
    27 
    28     //把XML數(shù)據(jù)轉(zhuǎn)換為BookEntity對象集
    29     private static List<BookEntity> convertToBooks(OMElement element)
    30             throws AxisFault{
    31         List<BookEntity> list=new ArrayList<BookEntity>();
    32         Iterator books=element.getChildElements();
    33         while(books.hasNext()){
    34             OMElement bookElement=(OMElement)books.next();
    35             BookEntity book=(BookEntity) BeanUtil.processObject(bookElement,
    36                 BookEntity.class, null, true, new DefaultObjectSupplier(), null);
    37             list.add(book);
    38         }
    39         return list;
    40     }
    41     
    42     //對OMElement元素進行遍歷,找到computer類型的節(jié)點
    43     private static OMElement getComputerElement(OMElement element){
    44         OMElement returnOMElement=(OMElement)element
    45             .getChildElements().next();
    46         OMElement publishingOMElement=(OMElement)returnOMElement
    47             .getChildElements().next();
    48         Iterator themes=publishingOMElement.getChildElements();
    49         OMElement theme=null;
    50         while(themes.hasNext()){
    51             theme=(OMElement)themes.next();
    52             OMAttribute themeName=(OMAttribute)theme.getAllAttributes().next();
    53             if(themeName.getAttributeValue().equals("computer"))
    54                break;
    55         }
    56         return theme;
    57     }
    58     
    59     //構(gòu)建請求文檔
    60     private static OMElement getBookRequest(String publishing){
    61         //新建OMFactory工廠
    62         OMFactory factory=OMAbstractFactory.getOMFactory();   
    63         
    64         //綁定OMNamespace,請求數(shù)據(jù)
    65         OMNamespace omNamespace=factory.createOMNamespace(
    66                 "http://serviceImpl.axis2","ns");     
    67         OMElement value=factory.createOMElement("publishing",omNamespace);   
    68         value.addChild(factory.createOMText(value,publishing.toString()));  
    69         
    70         //綁定請求方法名
    71         OMElement method=factory.createOMElement("getList",omNamespace); 
    72         method.addChild(value);  
    73         return method;  
    74     }
    75     
    76     private static void DisplayBook(BookEntity book){
    77         System.out.println("##Id##:"+book.getId()+"  ##Title##:"+book.getTitle()
    78             +"\n##Author##:"+book.getAuthor()+"  ##Type##:"+book.getType()
    79             +"  ##Publishing##:"+book.getPublishing()+"\n##Introduction##:\n"
    80             +book.getIntroduction()+"\n");
    81     }

    發(fā)送的SOAP請求


    顯示結(jié)果


     回到目錄

    七、Module 模塊獨立化處理方式

    7.1 Axis 2.x 信息處理流程

    Axis 2.x 對信息處理流程作出了較大幅的修改,在介紹模塊處理結(jié)構(gòu)前,需要簡單介紹一下 Axis 2.x 的信息處理機制。Axis 1.x 只接受請求-響應(yīng)的信息處理模式,而 Axis 2.x 支持 In-Only、In-Out 和 Robust-In 三種消息交換模式。而這三種消息交換機制是建立在 TransportListener 和 TransportSender 之上的,在 SOAP 信息進站時,系統(tǒng)會通過 TransportListener 進行監(jiān)聽。通過一系列處理后,最后會由 TransportSender 進行信息的回送。
    系統(tǒng)定義了 InFlow、OutFlow 兩種流用于處理服務(wù)器端的請求消息和響應(yīng)消息。而 InFaultFlow、OutFaultFlow 只會在請求或者響應(yīng)出現(xiàn)錯誤時才會被調(diào)用。當(dāng)TransportListener 監(jiān)聽到入站信息時會把信息送到 InFlow 流當(dāng)中,系統(tǒng)可通過修改 “ \WEB-INF\conf\axis2.xml” 配置文件,把多個 Phase 綁定到 InFlow 當(dāng)中。每個 Phase 相當(dāng)于一個階段,同一個階段可以綁定多個 Handler 進行處理。數(shù)據(jù)通過 InFlow 流處理后就會被發(fā)送到 MessageReceiver,在 services.xml 中會綁定對應(yīng)的 MessageReceiver 服務(wù)方法。最后通過 OutFlow 流對返回信息進行處理后,由 TransportSender 把 SOAP 響應(yīng)回發(fā)到客戶端。

     

     

     

    7.2 Module 模塊結(jié)構(gòu)

    Axis 2.x 把 Handler 放入Module 模塊當(dāng)中,進行了獨立化處理。每個 Module 模塊是一個容器,當(dāng)中可以包含多個 Handler 處理程序、第三方庫、模塊相關(guān)資源和模塊配置文件。系統(tǒng)把Module 模塊定義為后綴名為 “ *.mar ” 的文件,系統(tǒng)可通過 “ jar  cvf  myModule.mar  . ” 命令可以生成 *.mar 的模板文件。當(dāng)中必須包含 module.xml 文件對 Handler 進行部署,否則系統(tǒng)會無法識別此模塊。想要在某個 Web服務(wù)的 InFlow 流或 OutFlow 流中調(diào)用 Module 模塊中的 Handler,還需要修改 axis2.xml  文件,在phaseOrder 中加入自定義的 phase, 并綁定 Handler 的處理類。最后修改 “ services.xml ” 文件,在對應(yīng)此服務(wù)配置中加入 <module ref="ModuleName"> 字節(jié) 。
    下面先以一個簡單的例子,說明 Module 模塊的使用方式。在例子中將建立一個 MyModule 模塊,在模塊中加入一個 InputHandler 處理文件對 InFlow 流進行檢測。首先建立 org.apache.axis2.modules.Module 的子類 MyModule,此類是用于對模塊init 、engageNotify 等事件進行監(jiān)測的。然后建立 InputHandler 類,此類必須繼承 org.apache.axis2.engine.Handler 且實現(xiàn) org.apache.axis2.engine.Handler.AbstractHandler 接口的 public InvocationResponse invoke(MessageContext context) 方法,此方法的返回值 InvocationResponse 包括 CONTINUE,SUSPEND,ABORT 三個選項,可以"繼續(xù)"或者"停止"流的執(zhí)行。
    在流輸入時此方法將會被自動執(zhí)行,它所帶的 MessageContext 參數(shù)對象中將包括此服務(wù)的上下文信息。
    此例子的主要目的是為開發(fā)人員顯示一下在 InFlow 流可以獲取到的數(shù)據(jù)信息,所以在此先介紹一下 MessageContext 常用方法:

    方法  說明
    getCurrentMessageContext()  獲取當(dāng)前上下文對象
    getExecutedPhases()  獲取包含在此流中的 Phase 集合
    getAxisService()  獲取被調(diào)用的 AxisService 服務(wù)對象
    getEnvelope()  獲取 SOAP,在 InFlow 中,此方法將顯示該請求的 SOAP 信息
    getFrom()  獲取客戶端地址  
    getTo()  獲取服務(wù)地址

     MessageContext 常用方法


    當(dāng)中 getAxisService 方法所返回的 AxisService 對象正是當(dāng)前被調(diào)用的 Web服務(wù)對象。

    方法 說明
    getOperationContext() 返回當(dāng)前被調(diào)用的 OperationContext 上下文對象
    getOperations() 返回此服務(wù)所包含的所有 Operation 對象
    getParameters() 返回此服務(wù)的所包含的所有 Parameters 對象
    getFileName() 返回此*.aar 服務(wù)文件路徑
    getTargetNamespace() 返回此服務(wù)的 targetNamespace 名稱
    getEndpointName() 返回此服務(wù)的 Endpoint 名稱

     AxisService 常用方法

     1 public class MyModule implements Module{
     2  
     3      @Override
     4      public void applyPolicy(Policy arg0, AxisDescription arg1)
     5          throws AxisFault {
     6          // TODO Auto-generated method stub
     7      }
     8  
     9      @Override
    10      public boolean canSupportAssertion(Assertion arg0) {
    11          // TODO Auto-generated method stub
    12          return false;
    13      }
    14  
    15      @Override
    16      public void engageNotify(AxisDescription arg0) throws AxisFault {
    17          // TODO Auto-generated method stub
    18      }
    19  
    20      @Override
    21      public void init(ConfigurationContext arg0, AxisModule arg1)
    22              throws AxisFault {
    23          // TODO Auto-generated method stub
    24      }
    25  
    26      @Override
    27      public void shutdown(ConfigurationContext arg0) throws AxisFault {
    28          // TODO Auto-generated method stub
    29      }  
    30  }
    31  
    32  public class InputHandler
    33        extends AbstractHandler implements Handler{
    34      
    35      public InvocationResponse invoke(MessageContext context){
    36          //顯示當(dāng)前上下文信息
    37          System.out.println("##from:##\n  "+context.getFrom()
    38                  +"\n##to:##\n  "+context.getTo());
    39          //顯示所執(zhí)行的phase信息
    40          phasesMessageDisplay(context.getExecutedPhases());
    41          //顯示服務(wù)對象信息
    42          AxisService axisService=context.getAxisService();
    43          serviceMessageDisplay(axisService);
    44          //顯示當(dāng)前operation信息
    45          AxisOperation operation=context.getOperationContext().getAxisOperation();
    46          currentOperationDisplay(operation);
    47          //顯示服務(wù)的所有operation信息
    48          operationsMessageDisplay(axisService.getOperations());
    49          //顯示服務(wù)參數(shù)parameters信息
    50          parametersMessageDisplay(axisService.getParameters());
    51          return InvocationResponse.CONTINUE;
    52      }
    53      
    54      //顯示所執(zhí)行的phases
    55      private void phasesMessageDisplay(Iterator<Handler> iterator){
    56          String data="##phaseList:##\n";
    57          while(iterator.hasNext()){
    58              Handler handler=(Handler)iterator.next();
    59              data+="  "+handler.getName();  
    60          }
    61          System.out.println(data);
    62      }
    63      
    64      //顯示服務(wù)信息
    65      private void serviceMessageDisplay(AxisService axisService){
    66          System.out.println("\n##serviceFile:##\n  "+axisService.getFileName()+ 
    67              "\n##targetNamespace:##\n  "+axisService.getTargetNamespace()+
    68              "\n##endpointName##:\n  "+axisService.getEndpointName()+"\n");
    69      }
    70      
    71      //顯示當(dāng)前Operation信息
    72      private void currentOperationDisplay(AxisOperation operation){
    73          System.out.println("##currentOperation:##\n  name:"
    74                  +operation.getName().getLocalPart()+"\n  messageReceive:"
    75                  +operation.getMessageReceiver().toString()+"\n");
    76      }
    77      
    78      //顯示服務(wù)的所有Operation信息
    79      private void operationsMessageDisplay(Iterator operations){
    80          while(operations.hasNext()){
    81              AxisOperation operation=(AxisOperation)operations.next();
    82              System.out.println("##operation:##\n  name:"
    83                  +operation.getName().getLocalPart()+"\n  messageReceive:"
    84                  +operation.getMessageReceiver().toString());
    85          }
    86          System.out.println();
    87      }
    88      
    89      //顯示parameter信息
    90      private void parametersMessageDisplay(List<Parameter> parameters){
    91          for(Parameter parameter:parameters){
    92              System.out.println("##parameter:##\n  name:"+parameter.getName()
    93                      +"\n  value:"+parameter.getValue().toString());
    94          }
    95      }
    96  }

    在 “ \WebRoot\META-INF\ ” 內(nèi)加入 “ module.xml ” 配置文件

    1 <module name="myModule" class="axis2.module.MyModule">
    2     <InFlow>
    3        <handler name="inputHandler" class="axis2.handler.InputHandler">
    4           <order phase="orderInPhase"/>
    5        </handler>
    6     </InFlow>
    7 </module>

    把 “module.xml ” 配置文件(包含 “ META-INF ”文件夾)和編譯后的 MyModule.class、InputHandler.class 加入到自定義文件夾,使用命令提示符進行入自定義文件夾內(nèi)輸入 “ jar  cvf  myModule.mar  . ” 命令生成 “ myModule.mar ” 包,把生成的包加入 “\WEB-INF\modules ” 文件夾內(nèi)。
    最后修改 “ \WEB-INF\conf\axis2.xml” 配置文件,加入自定義的 phase 配置。此時重啟系統(tǒng),即完成了 myModule.mar 自定義模塊的配置。

    注意:自定義 handler 可以在 axis2.xml 或者 module.xml 中進行綁定。

    axis2.xml 中所配置的是全局變量,如果直接在 axis2.xml 文件中加入對 handler 進行綁定,那所有的服務(wù)在 InFlow 和 OutFlow 中都執(zhí)行此 handler。
    如果只在 axis2.xml 中建立自定義 phase,然后在 module.xml 中綁定 handler,那只有在服務(wù)綁定此 module 時,該 handler 才會被執(zhí)行 。配置應(yīng)該按需要而定,一般只有登錄、日志記錄、系統(tǒng)信息監(jiān)視等 handler 才會在 axis2.xml 中直接綁定。

    1     <phaseOrder type="InFlow">
    2         <phase name="orderInPhase">
    3            <handler name="inputHandler" class="axis2.handler.InputHandler"/>
    4         </phase>
    5     </phaseOrder>

    想要在某 Web 服務(wù)中調(diào)用此模塊,只需要修改對應(yīng)的 services.xml 配置文件,在服務(wù)配置內(nèi)加入“ <module ref=‘myModule’ /> ” 字節(jié)即可。

     1 <service name="PersonService">  
     2    <description>This is a sample Web Service.</description>
     3    <!--使用myModule模塊-->  
     4    <module ref="myModule"/>
     5    <!-- ServiceClass指定實現(xiàn)服務(wù)的類。 -->  
     6    <parameter name="ServiceClass" locked="false">axis2.serviceImpl.PersonServiceImpl</parameter>  
     7    <!-- operation 與Java Class中方法名對應(yīng)。   -->
     8    <operation name="GetPerson">  
     9       <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>  
    10    </operation>
    11    <operation name="GetList">  
    12       <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>  
    13    </operation> 
    14    <operation name="GetListByName">  
    15       <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>  
    16    </operation> 
    17 </service>   

    在啟動此Web服務(wù),調(diào)用 GetPerson 服務(wù)方法時,InputHandler 將會對服務(wù)流進行處理,顯示測試結(jié)果:


     

    7.3 Module 實用方式

    以上對 Module 的使用方式進行了簡單的介紹,下面想以一個更為實際的訂單管理例子介紹一下 Module 的用途。在Web服務(wù)項目當(dāng)中,很多的服務(wù)在操作前都需要先進行登錄驗證,所以下面例子當(dāng)中會把用戶登錄功能獨立開來,作為一個自定義 Handler 置于模塊當(dāng)中,這樣可以使登錄服務(wù)的功能更為獨立,易于管理。用戶在調(diào)用 OrderService 服務(wù)時,會先在頭文件中加入用戶信息, 在服務(wù)端接收到 SOAP 請求時,在 InFlow 流中加入 OrderInputHandler 進行處理,獲取頭文件信息進行登錄,登錄成功就會在 Session 中記錄 User 對象信息。
    像 Order 管理這類服務(wù)中,訂單費用的計算往往是一個長期不變的規(guī)則,但銷售商很多時候會進行產(chǎn)品的抽獎,優(yōu)惠等銷售策略,這些策略都是短期的,具有多變性。如果直接把這些業(yè)務(wù)規(guī)則寫入 OrderService 服務(wù)中,OderService 就會經(jīng)常需要修改。此時,可以嘗試利用 OutFlow 流 ,建立 OrderOutputHandler 對完成操作的 Order 進行檢測。若通過得獎規(guī)則,則在SOAP返還信息的頭文件中加入獎勵信息。
    由于本節(jié)的目的主要是為了展示 Module 的獨立性與靈活性,所以省略了 OrderManager、UserManager、FavourableManager 等操作對象。
    首先建立 OrderInputHandler 在 SOAP 信息進入 InFlow 流時進行登錄處理。
    然后建立 OrderOutputHandler 在 SOAP 信息進行 OutFlow 時對已處理Order對象進行檢測。

      1 public class MyModule implements Module{
      2     
      3         @Override
      4         public void applyPolicy(Policy arg0, AxisDescription arg1)
      5             throws AxisFault {
      6             // TODO Auto-generated method stub
      7         }
      8     
      9         @Override
     10         public boolean canSupportAssertion(Assertion arg0) {
     11             // TODO Auto-generated method stub
     12             return false;
     13         }
     14     
     15         @Override
     16         public void engageNotify(AxisDescription arg0) throws AxisFault {
     17             // TODO Auto-generated method stub    
     18         }
     19     
     20         @Override
     21         public void init(ConfigurationContext arg0, AxisModule arg1)
     22                 throws AxisFault {
     23             // TODO Auto-generated method stub
     24         }
     25     
     26         @Override
     27         public void shutdown(ConfigurationContext arg0) throws AxisFault {
     28             // TODO Auto-generated method stub
     29         }  
     30     }
     31     
     32     public class OrderInputHandler 
     33        extends AbstractHandler implements Handler {
     34     
     35         public InvocationResponse invoke(MessageContext context){
     36             //判斷被調(diào)用的是否OrderSerivce的addOrder方法
     37             if(context.getOperationContext().getAxisOperation()
     38                     .getName().getLocalPart().equals("addOrder")){
     39                 //獲取頭文件信息
     40                 SOAPHeader head=context.getEnvelope().getHeader();
     41                 //把頭文件信息轉(zhuǎn)換成User對象進行登錄
     42                 String[] userMes=head.getFirstElement().getText().split(",");
     43                 //用戶登錄
     44                 UserEntity user=UserManager.Login(userMes[0],userMes[1]);
     45                 .......
     46                 if(user!=null){
     47                    //登錄成功記錄User
     48                    SessionContext session=context.getSessionContext();
     49                    if(session.getProperty("User")==null)
     50                        session.setProperty("User", user);
     51                 } 
     52             }
     53             return InvocationResponse.CONTINUE;
     54         }
     55     }
     56     
     57     public class OrderOutputHandler 
     58         extends AbstractHandler implements Handler{
     59          
     60         public InvocationResponse invoke(MessageContext context){
     61             //判斷被調(diào)用的是否OrderSerivce的addOrder方法
     62             if(context.getOperationContext().getAxisOperation()
     63                     .getName().getLocalPart().equals("addOrder")){
     64               //獲取返回信息的SOAPBody,判斷訂單總體價格是否高于 200 dollar
     65               SOAPBody body=context.getEnvelope().getBody();
     66               OMElement element=body.getFirstElement();
     67               try {
     68                  OrderEntity order = (OrderEntity) BeanUtil.processObject(element,
     69                      OrderEntity.class, null, true, new DefaultObjectSupplier(), null);
     70                 
     71                  //總體價格高于 200 dollar的訂單在頭文件中輸入獲獎信息
     72                  if(order.getTotalPrice()>200){
     73                  //在數(shù)據(jù)庫中記錄獲獎訂單
     74                  Favourable favourable=FavourableManager.addOrder(order); 
     75                  .......
     76                  //修改頭文件,加入獲獎信息 
     77                  setHead(context.getEnvelope().getHeader(),favourable);
     78               } catch (AxisFault e) {
     79                  e.printStackTrace();
     80               }      
     81           }
     82           return InvocationResponse.CONTINUE;
     83         }
     84         
     85         //修改頭文件,加入獲獎信息
     86         private void setHead(SOAPHeader head,favourable){
     87             OMFactory factory=OMAbstractFactory.getOMFactory(); 
     88             OMNamespace omNamespace=factory.createOMNamespace(
     89                     "http://serviceImpl.axis2","ns");    
     90             OMElement element=factory.createOMElement("favourable",omNamespace);
     91             element.setText("Congratulations! Price is higher than 200 dollar ......");
     92             //加入favourable 信息
     93             .........
     94             head.addChild(element);
     95         }
     96     }
     97     
     98     public class OrderEntity implements Serializable {
     99         private Integer id;
    100         private String orderCode;
    101         private Double totalPrice;
    102         .........
    103      
    104         public OrderEntity(Integer id,String orderCode,Double totalPrice,........){
    105             this.id=id;
    106             this.orderCode=orderCode;
    107             this.totalPrice=totalPrice;
    108             ........
    109         }
    110         ..........
    111     }

    完成自定義Handler后,進行 module.xml 配置,分別在 InFlow 流 OutFlow 綁定 OrderInputHandler 和 OrderOutputHandler

     1 <module name="myModule" class="axis2.module.MyModule">
     2     <InFlow>
     3        <handler name="orderInputHandler" class="axis2.handler.OrderInputHandler">
     4           <order phase="orderInPhase"/>
     5        </handler>
     6     </InFlow>
     7     <OutFlow>
     8         <handler name="orderOutputHandler" class="axis2.handler.OrderOutputHandler">
     9             <order phase="orderOutPhase"/>
    10         </handler>
    11     </OutFlow>
    12 </module>

    修改 axis2.xml 文件,建立自定義的 phase ,在 InFlow 流和 OutFlow 流中加入 orderInPhase 和 orderOutPhase 。

    1      <phaseOrder type="InFlow">
    2         <phase name="orderInPhase"/>
    3      </phaseOrder>
    4      <phaseOrder type="OutFlow">
    5          <!-- 調(diào)用自定義模塊進行處理 -->
    6          <phase name="orderOutPhase"/>
    7      </phaseOrder>

    建立 Web 服務(wù)OrderService ,當(dāng)調(diào)用 addOrder 前先檢測用戶是否登錄成功,若用戶未登錄則釋放出異常。若登錄成功,把輸入的Order對象加入數(shù)據(jù)庫,然后把處理后的 Order 轉(zhuǎn)換為OMElement 返還到客戶端。

     1     public interface OrderService {
     2        OMElement addOrder(OMElement element) throws Exception;
     3     } 
     4     
     5     public class OrderServiceImpl implements OrderService{
     6         
     7         @Override
     8         public OMElement addOrder(OMElement element) throws Exception{
     9             //驗證是否登錄成功
    10             if(isLogged()){
    11                 //把訂單加入數(shù)據(jù)庫,把更新后的訂單返回客戶端
    12                 OrderEntity order = (OrderEntity) BeanUtil.processObject(
    13                    element.getFirstElement(),OrderEntity.class, 
    14                    null, true, new DefaultObjectSupplier(), null);
    15                 //加入訂單,計算總體價格,Code號碼等信息
    16                 OrderEntity orderRefresh=OrderManager.addOrder(order);
    17                 .......
    18                 //把修改后order對象轉(zhuǎn)換為OMElement
    19                 XMLStreamReader reader=BeanUtil.getPullParser(orderRefresh);
    20                 StreamWrapper parser=new StreamWrapper(reader);
    21                 OMXMLParserWrapper stAXOMBuilder=OMXMLBuilderFactory
    22                   .createStAXOMBuilder(OMAbstractFactory.getOMFactory(), parser);
    23                 return  stAXOMBuilder.getDocumentElement();
    24             }
    25             else
    26                 throw new Exception();
    27         }
    28         
    29         //驗證用戶是否已經(jīng)登錄
    30         private boolean isLogged(){
    31             MessageContext context=MessageContext.getCurrentMessageContext();
    32             SessionContext session=context.getSessionContext();
    33             return session.getProperty("User")!=null;    
    34         }
    35     }

    在 services.xml 文件加入 module 節(jié)點

     1 <service name="OrderService">  
     2    <description>This is a sample Web Service.</description>  
     3    <module ref="myModule"/>
     4    <!--  ServiceClass指定實現(xiàn)服務(wù)的類。 -->  
     5    <parameter name="ServiceClass" locked="false">axis2.serviceImpl.OrderServiceImpl</parameter>  
     6    <!-- operation 與Java Class中方法名對應(yīng)。   -->
     7    <operation name="addOrder">  
     8       <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>  
     9    </operation>
    10  </service>   

    當(dāng)調(diào)用OrderService 服務(wù)后,數(shù)據(jù)進入 OutFlow 流后系統(tǒng)將檢測返還數(shù)據(jù),若 Order 符合得獎條件,OrderOutputHandler 將在SOAP頭部加入得獎信息。下面是 totalPrice 超過 200 dollor (符合得獎條件) 所返回的SOAP信息。


     

    在客戶端發(fā)送 OrderService.addOrder 請求時,在頭文件加入用戶userName,password等資料。為了在使用Session存儲User對象,需要在客戶端使用options.setManageSession(bool)方法打開 sessionContext 。由于使用方式與 Axis1.x 較為相像,在此不再詳細說明了。

     1      public static void main(String[] args) throws RemoteException, OrderServiceExceptionException {
     2          // TODO Auto-generated method stub
     3          excute();
     4      }
     5      
     6      public static void excute() throws AxisFault{
     7          EndpointReference targetEndpoint=new EndpointReference(
     8                  "http://leslie-laptop:8080/axis2-1.6.2/services/OrderService"); 
     9          Options options=new Options();   
    10          options.setManageSession(true);
    11          options.setTo(targetEndpoint); 
    12         
    13          //設(shè)置傳輸方式
    14          //可使用 TRANSPORT_JMS;TRANSPORT_HTTP;TRANSPORT_MAIL;TRANSPORT_TCP;
    15          options.setTransportInProtocol(Constants.TRANSPORT_HTTP);   
    16          
    17          //把設(shè)置的地址、傳輸方式綁定到Service請求當(dāng)中
    18          ServiceClient sender=new ServiceClient();   
    19          sender.setOptions(options);   
    20          
    21          //設(shè)置請求的 SOAP 信息
    22          OMElement requestOMElement=getOrderRequest(new OrderEntity(-1,null,200.5,......));   
    23          //在頭文件中加入用戶資料
    24          sender.addHeader(setHead());
    25          OMElement responseOMElement=sender.sendReceive(requestOMElement);   
    26         
    27          //對返回的SOAP進行處理,顯示返回值
    28          OrderEntity order=convertToOrder(responseOMElement);
    29          displayOrderProperty(order);
    30      }
    31      
    32      //在頭文件中加入用戶資料    
    33      private static OMElement setHead(){
    34          //新建OMFactory工廠
    35          OMFactory factory=OMAbstractFactory.getOMFactory();   
    36          //綁定OMNamespace,請求數(shù)據(jù)
    37          OMNamespace omNamespace=factory.createOMNamespace(
    38                  "http://serviceImpl.axis2","ns");     
    39          //加入用戶資料
    40          OMElement user=factory.createOMElement("User",omNamespace); 
    41          user.setText("Leslie,12345678");
    42          return user;
    43      }
    44      
    45      private static OMElement getOrderRequest(OrderEntity order){
    46          //新建OMFactory工廠
    47          OMFactory factory=OMAbstractFactory.getOMFactory();     
    48          //綁定OMNamespace
    49          OMNamespace omNamespace=factory.createOMNamespace(
    50                  "http://serviceImpl.axis2","ns");     
    51          //綁定請求方法名
    52          OMElement method=factory.createOMElement("addOrder",omNamespace); 
    53  
    54          //把order對象轉(zhuǎn)換為OMElement
    55          javax.xml.stream.XMLStreamReader reader=BeanUtil.getPullParser(order);
    56          StreamWrapper parser=new StreamWrapper(reader);
    57          OMXMLParserWrapper stAXOMBuilder=OMXMLBuilderFactory
    58                  .createStAXOMBuilder(OMAbstractFactory.getOMFactory(), parser);
    59          OMElement param=stAXOMBuilder.getDocumentElement();
    60          
    61          method.addChild(param);
    62          return method;
    63      }
    64      
    65      //把返回OMElement對象轉(zhuǎn)換成 person對象 
    66      private static OrderEntity convertToOrder(OMElement element) 
    67              throws AxisFault{
    68          OrderEntity order =null;
    69          OMElement omElement = element.getFirstElement().getFirstElement();
    70          String localName=element.getLocalName().toLowerCase();
    71          if (localName.equals("orderentity")) {
    72             order = (OrderEntity) BeanUtil.processObject(element,
    73             OrderEntity.class, null, true, new DefaultObjectSupplier(), null);      
    74          }
    75          return order;
    76      }
    77      //顯示Order數(shù)據(jù)
    78      private static void displayOrderProperty(OrderEntity order){
    79          System.out.println("Id:"+order.getId()+"  Code:"+order.getOrderCode()
    80             +"  TotalPrice:"+ order.getTotalPrice());
    81      }

    發(fā)送的SOAP請求


     

     回到目錄 

    八、異步調(diào)用Web服務(wù)

    在 Axis 1.x 中服務(wù)只支持 “請求-回復(fù)” 的操作方式,客戶端在發(fā)送請求后將處于等待的狀態(tài),在Web服務(wù)操作時間較長的情況下,這種操作方式將影響了系統(tǒng)的效率。從 Axis 2.x 開始客戶端支持異步操作的方式,在發(fā)送請求后,系統(tǒng)將使用異步線程綁定回調(diào)操作。在發(fā)出請求后,客戶端無需再處理于長期等待的狀態(tài)。生成異步操作的方法有很多,比較簡單的是使用 WSDL2Java 的 “-a” 命令:
    WSDL2Java -uri http://localhost/axis2-1.6.2/services/PersonSerivce.wsdl -p 包名 -o 文件夾 -a
    所生成的客戶端會包含一個 ServiceCallbackHandler 類,下面的例子當(dāng)中,只要實現(xiàn)了 PersonServiceCallbackHandler 類的 receiveResultgetList 方法,在調(diào)用 personServiceStub.startgetList(PersonServiceStub.GetList , PersonServiceCallbackHandler)方法后,系統(tǒng)將釋放主線程。當(dāng)接收到服務(wù)端的返還信息后,信息將交由 PersonServiceCallbackHandler 所綁定的方法進行處理。

    服務(wù)端

    1 public class PersonService{
    2 
    3     public List<PersonEntity> getList(){
    4         List<PersonEntity> list=new ArrayList<PersonEntity>();
    5         list.add(new PersonEntity(1,"Leslie",32,"tianhe"));
    6         list.add(new PersonEntity(2,"Elva",28,"henan"));
    7         return list;
    8     }
    9 }

    客戶端

     1     public static void main(String[] args)
     2             throws InterruptedException, RemoteException {
     3         // TODO Auto-generated method stub
     4         threadMessage("start "); 
     5         //建立服務(wù)對象
     6         PersonServiceStub personService=new PersonServiceStub();        
     7         PersonServiceStub.GetList getList=new PersonServiceStub.GetList();
     8         //建立回調(diào)函數(shù)
     9         PersonServiceCallbackHandler callback=new PersonServiceCallbackHandler(){
    10             public void receiveResultgetList(GetListResponse response){
    11                 threadMessage("callback ");
    12                 PersonEntity[] list=response.get_return();
    13                 for(Integer n=0;n<list.length;n++)
    14                     displayPersonProperty(list[n]);
    15             }
    16         };
    17         //啟動異步服務(wù)
    18         personService.startgetList(getList,callback);
    19         Thread.sleep(500);
    20     }
    21 
    22     //顯示線程id
    23     private static void threadMessage(String data){
    24            Thread thread=Thread.currentThread();
    25            System.out.println(data +"threadId: "+thread.getId());
    26     }
    27     
    28     //顯示對象信息
    29     private static void displayPersonProperty(PersonEntity person){
    30         System.out.println("Id:"+person.getId() +"  Name:"
    31            +person.getName() +"  Age:"+ person.getAge() 
    32            +"  Address:"+person.getAddress() );
    33     }

    測試結(jié)果


     回到目錄

     

    本章小結(jié)

    Aixs 的主要特點在于其操作的靈活性,它能對請求和回發(fā)的 SOAP 信息直接進行處理,在頭文件或者自定義節(jié)點中加入數(shù)據(jù)。特別在Axis 2.x 引入 AXIOM 后,其優(yōu)點更為突出。它使用 StAX(Streaming API for XML ) 拉式(Pull)解析器,可盡量減輕對系統(tǒng)資源的壓力。Axis 2.x 使用 Module 模塊化的部署方式,使系統(tǒng)功能分割更為簡單, Module 可以獨立于服務(wù)進行開發(fā)。為了解決客戶端為等待返回數(shù)據(jù)而長時間處于柱塞狀態(tài),Axis 2.x 還加入異步操作的方法,提高了客戶端的運行效率。
    由于本人并非 JAVA 方面的專家,文章難免存在錯誤之處,敬請讀者點評。
    對JAVA開發(fā)有興趣的朋友歡迎加入
    QQ群:Java高級編程(174850571)
    騰訊微博群:數(shù)碼化時代(62916150)
    新浪微博群: 一切皆是“云”(1181103)

    作者:風(fēng)塵浪子

    http://m.tkk7.com/Leslies2/archive/2012/09/14/leslieBlog-java-axis.html

    原創(chuàng)作品,轉(zhuǎn)載時請注明作者及出處

     

     

     

     

     

     

    posted on 2012-09-14 10:33 風(fēng)塵浪子 閱讀(2783) 評論(0)  編輯  收藏 所屬分類: Java遠程通信技術(shù)


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     

    導(dǎo)航

    統(tǒng)計

    公告

     個人簡介

    02年畢業(yè)于中山大學(xué)物理系,專門從事.NET、JAVA的項目開發(fā),研究大型企業(yè)系統(tǒng)架構(gòu)。對領(lǐng)域驅(qū)動設(shè)計DDD、面向服務(wù)架構(gòu)SOA、分布式開發(fā)、.NET與JAVA的相互調(diào)用等方面有著深厚的興趣。本博客中的文章皆屬原創(chuàng),轉(zhuǎn)載時請注明出處。


    Java高級編程

    技術(shù)交流
    歡迎加入以下小組共同探討
    QQ群:
    JAVA 高級編程 174850571
    騰訊微博群:
    數(shù)碼化時代 62916150
    新浪微博群:
    一切皆是“云” 1181103

    常用鏈接

    留言簿

    隨筆分類(1)

    隨筆檔案(2)

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 国产无限免费观看黄网站| 成年18网站免费视频网站| 亚洲中文字幕无码不卡电影| 亚洲成a人无码亚洲成www牛牛| 国产成人精品免费视| 亚洲av成人无码久久精品| 国产精品综合专区中文字幕免费播放| 日韩在线看片免费人成视频播放| 亚洲图片中文字幕| 8x8×在线永久免费视频| 亚洲成a人片在线观看日本| 久久一区二区免费播放| 国产国拍亚洲精品福利 | 免费jjzz在在线播放国产| 亚洲人成网站免费播放| 一二三四在线播放免费观看中文版视频 | 亚洲AV日韩精品久久久久久久| 羞羞视频免费网站在线看| 亚洲性日韩精品一区二区三区 | 亚洲AV无码日韩AV无码导航 | 永久免费的网站在线观看| 亚洲同性男gay网站在线观看| 18女人腿打开无遮掩免费| 久久亚洲AV无码精品色午夜| 日本免费一区二区三区| 亚洲综合在线观看视频| 91精品手机国产免费| 亚洲视频一区在线| 日本免费网站视频www区| 亚洲人成在久久综合网站| 免费A级毛片无码无遮挡内射| 亚洲中文字幕人成乱码| 成在人线AV无码免费| 看亚洲a级一级毛片| 亚洲国产精品无码久久久久久曰 | 亚洲韩国在线一卡二卡| 免费观看无遮挡www的视频| 亚洲人成网站看在线播放| 免费无码又爽又刺激高潮的视频| 亚洲6080yy久久无码产自国产| 哒哒哒免费视频观看在线www|