WebService基本

zxc123e發表於2015-07-25

1. 介紹和說明

Webservice的一個最基本的目的就是提供在各個不同平臺的不同應用系統的協同工作能力。 它就是一個可以遠端呼叫的類,或者說是元件。
WSDL:(Web Services Description Language) WSDL 檔案是一個 XML 文件,用於說明一組 SOAP 訊息以及如何交換這些訊息,wsld是服務者與消費者之間建立橋樑的關鍵。
Soap:(Simple Object Access Protocol)簡單物件存取協議。是XML Web Service 的通訊協議。當使用者訪問到你的WSDL描述文件後,他通過可以SOAP呼叫你建立的Web服務中的一個或多個操作。SOAP是XML文件形式的呼叫方法的規範,它可以支援不同的底層介面,像HTTP(S)或者SMTP。
各種語言都對webservice進行支援,java中我們通過cxf來實現webservice,下面我們看一下如何通過cxf來實現我們的服務。

服務端公佈服務:

        JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
        factory.setServiceClass(Student.class);
        factory.setAddress("http://localhost:8080/myservice");
        Server server = factory.create();
        server.start();

這裡使用的cxf內嵌的伺服器Jetty來發布服務,其中Student類實現了Person介面,裡面有一個方法sayHello,注意公佈服務的時候一定要使用實現類,只有實現類才能提供服務。

客戶端消耗服務:

JaxWsProxyFactoryBean client = new JaxWsProxyFactoryBean();
        client.setServiceClass(Person.class);
        client.setAddress("http://localhost:8080/myservice");
        Person std = (Person)client.create();

        System.out.println(std.sayHello("chm"));

客戶端消費服務,在本地生成了遠端的一個程式碼,我們從代理得到遠端的物件必須宣告為一個介面(動態代理)。

2. wsdl檔案結構

訪問上面公佈的服務地址http://localhost:8080/myservice?wsld會看到這樣一個檔案

<?xml version='1.0' encoding='UTF-8'?><wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://test.chm.com/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" name="StudentService" targetNamespace="http://test.chm.com/">
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://test.chm.com/" elementFormDefault="unqualified" targetNamespace="http://test.chm.com/" version="1.0">
  <xs:element name="sayHello" type="tns:sayHello"/>
  <xs:element name="sayHelloResponse" type="tns:sayHelloResponse"/>

  <xs:complexType name="sayHello"> <!-- 引數型別 包裝成一個類 -->
    <xs:sequence>
      <xs:element minOccurs="0" name="name" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="sayHelloResponse"> <!-- 返回值型別 包裝成一個類 -->
    <xs:sequence>
      <xs:element minOccurs="0" name="helloResult" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

</xs:schema>
</wsdl:types>
  <wsdl:message name="sayHelloResponse">
    <wsdl:part element="tns:sayHelloResponse" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="sayHello">
    <wsdl:part element="tns:sayHello" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:portType name="Person">
    <wsdl:operation name="sayHello"> <!-- name對應介面中方法名 -->
      <wsdl:input message="tns:sayHello" name="sayHello">
    </wsdl:input>
      <wsdl:output message="tns:sayHelloResponse" name="sayHelloResponse">
    </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="StudentServiceSoapBinding" type="tns:Person">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="sayHello"><!-- name對應實現類中方法名 -->
      <soap:operation soapAction="" style="document"/>
      <wsdl:input name="sayHello">
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="sayHelloResponse">
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="StudentService">
    <wsdl:port binding="tns:StudentServiceSoapBinding" name="StudentPort">
      <soap:address location="http://localhost:8080/myservice"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

看懂這個檔案需要xml schema的一些知識,這裡就不做介紹了,wsld檔案結構從上往下是依次依賴與被依賴的關係,wsld:types標籤裡面描述了方法引數和返回值的型別,wsld:message依賴wsld:types中定義的元素,而又被下面的wsdl:portType裡面的元素所依賴,wsld描述了介面的資訊,而下面wsdl:binding介面實現類的資訊,wsdl:operation描述的是方法的資訊,所以wsdl:portType和wsdl:binding裡面wsdl:operation標籤中的name屬性值是必須一樣的,這對應到java程式碼中就是類實現介面並重新介面中的方法,最後wsdl:service描述了公佈服務的地址資訊。
瞭解以上資訊後,我們就可以手動編寫wsdl,然後通過cxf提供的工具來生成java程式碼,這種方式開發webservice我們稱為契約優先(自頂向下)。

生成java程式碼命令:

  • D:\apache-cxf-3.0.5\bin>wsdl2java -server -impl -frontend jaxws21
    E:/myservice.
    生成服務端程式碼,包括實現類
  • D:\apache-cxf-3.0.5\bin>wsdl2java -client -frontend jaxws21
    E:/myservice.
    生成服客戶端碼
  • D:\apache-cxf-3.0.5\bin>wsdl2java -all -frontend jaxws21 E:/myservice.
    同時生成客戶端和服務端程式碼

3. 編排與反編排

當我們從客戶端呼叫webservice方法時,經歷這樣一個過程,先將我們的請求引數當成一個整體編排成soap訊息傳送個服務端,服務端接收到訊息後進行反編排生成java程式碼,然後服務端處理完,將返回的內容依然編排成soap訊息返回給客戶端,客戶端接收訊息後反編排。編排與反編排可以通過JaxbContext這個類來實現,這是jdk裡面的一個類。JAXB(Java Architecture for XML Binding)是一個業界的標準,cxf有對應jaxb的實現。

try {
            JAXBContext context = JAXBContext.newInstance(Person.class);
            Marshaller marshaller = context.createMarshaller();
            Person person = new Person();
            person.setName("zhangsan");
            person.setAge(30);
            marshaller.marshal(person, System.out);

            System.out.println();
            String person2 = "<person><name>lisi</name><age>20</age></person>";

            Unmarshaller unmarshaller = context.createUnmarshaller();
            Person p = (Person)unmarshaller.unmarshal(new StringReader(person2));
            System.out.println(p.getName());

        } catch (JAXBException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

4.TcpMon和JMeter的使用

TcpMon用於擷取soap訊息。
JMeter用於壓力測試,當然除了測試webservice還可以做許多其他的測試。這裡我需要TcpMon擷取的soap訊息進行測試。