Web服务和SOA(四)

时间:2022-10-24 20:58:26
 

使用SOAP协议来实现SOA服务

Soap是简单对象访问协议(Simple Object Access Protocal)的缩写,它是由W3C定义的Web服务的实现标准。基本说来,它定义了要交换的消息的结构,SOAP消息由信封、消息头和消息体构成。下面您会看到,SOAP协议针对问题的复杂程度不同,其定义的层次也不尽相同。SOAP提供了很多强大的功能,其中包括:

(1)     能自动生成消息交换过程中所需要的类;

(2)     自动生成Web服务描述符(WSDL)

(3)     能自动从Web服务的WSDL中生成客户端类;

(4)     能够使用HTTP之外的协议(SMTPJMS)进行消息传输;

(5)     提供了消息验证机制;

(6)     能够建立有状态的会话;

为了让您对该协议的实现有一个比较直观的了解,我们还是以前面的例子,及JDK6自带的功能来定义和发布Web服务。我们前面的例子其实是利用JAXB库对XML消息文档和Java对象之间进行自动绑定,这里我们使用JAX-WS库进行这个操作。JAX-WS库能明显提高软件层的抽象化层次。

现在,让我们看看使用SOAP创建一个插入和更新的Web服务是何其简单:

代码清单14 – 使用JAX-WS注解创建SOAP服务

  1. package com.packt.soajava.soap.service.item;
  2. import javax.jws.WebMethod;
  3. import javax.jws.WebService;
  4. import javax.xml.ws.Endpoint;
  5. import com.packt.soajava.model.item.Item;
  6. import com.packt.soajava.model.item.Outcome;
  7. @WebService
  8. public class ItemWs {
  9. @WebMethod
  10. public Outcome insert(Item item) {
  11. //Insert item ...
  12. System.out.println("Inserting item "+item.getId()); 
  13. Outcome outcome = new Outcome();
  14. outcome.setRetCode("OK");
  15. outcome.setRetMessage("Item was inserted successfully");
  16. return outcome;
  17. }
  18. @WebMethod
  19. public Outcome update(Item item) {
  20. //Update item ...
  21. System.out.println("Updating item "+item.getId());
  22. Outcome outcome = new Outcome();
  23. outcome.setRetCode("OK");
  24. outcome.setRetMessage("Item was updated successfully");
  25. return outcome;
  26. }

您可以看到,上面的代码非常简洁,抽象化层次很高,它并不需要那些序列化和反序列化的代码,它只包含了那些必需的代码。用SOAP实现Web服务和我们前面介绍的方法(POX-over-HTTPREST)都不尽相同。当我们使用基本的POX-over-HTTP方法开发Web服务时,我们需要为某个功能(比如商品这个业务对象上的功能)创建几个Servlets;在使用REST时我们需要新建一个类,而且REST中需要设计的业务方法正好和HTTP谓词相一致而已。但使用SOAP协议,我们可以在Web服务中定义多种方法,每种方法都相互独立,只要它们的方法签名不同即可。

为了发布上面的Web服务,我们还需要完成以下几步。首先,我们需要生成消息交换中所需要的类,这可通过JDK6自带的wsgen工具完成,请打开命令行并输入下列命令:

<JDK6_HOME>/bin/wsgen -cp <ProjectClassesRoot> -d <ProjectSourceRoot> -keep com.packt.soajava.soap.service.item.ItemWs

上面的命令将生成服务所需要的类,并把这些新生成的类放到<ProjectSourceRoot>(-d选项)所定义的路径中,-cp选项定义了ItemWs类所在的类路径。(译者注,在我的机器上,我运行的命令为:wsgen -cp C:/carl/workspace/SoaBookPoxHttp/WebRoot/WEB-INF/classes/ com.packt.soajava.soap.service.item.ItemWs -d C:/carl/workspace/SoaBookPoxHttp/src)。运行上述命令后,您会发现您的项目源文件夹中新增了一个新包(com.packt.soajava.soap.service.item.jaxws),这个包中有4个类。实际上,每个Web服务方法将产生两个类,其中的一个类名和Web服务方法名相同但大写首字母,另一个类名由方法名加Response构成。

现在,我们就可以发布Web服务了,JDK6主要使用了原型使Web服务的发布变得异常简单,您只需要写一个主类,运行下面一行代码即可。

Endpoint.publish( "http://localhost:8001/SoaBookSOAP_server/itemWs", new ItemWs());

到此为止,我们就完成了SOAP形式的Web服务的发布,当然,您也可以修改上面URI中的地址和端口号。

那我们怎样才能检测我们的Web服务已经正确发布了呢?最简单的方法是打开浏览器,输入下面的地址,请求该服务的WSDL

http://localhost:8001/SoaBookSOAP_server/itemWs?WSDL

您会在浏览器中看到由SOAP自动生成的WSDL(Web服务描述语言),其内容代表了Web服务的结构,WSDL文件对客户端非常重要,客户端可以依据它来自动生成客户端需要的类。JDK6自带的wsimport工具可以根据WSDL在客户端自动生成需要的类,其用法如下:

<JDK6_HOME>/bin/wsimport -d <ClientProjectSourceRoot> -p com.packt.soajava.soap.client.test.item –keep http://localhost:8001/SoaBookSOAP_server/itemWs?WSDL

上面的命令可以在客户端生成需要的类,并把它们放到客户端项目文件夹中(-d选项指定)-p选项是为客户端生成的类指定包名(译者注:我本机上运行的示例命令为:wsimport -d C:/temp/ -p com.packt.soajava.soap.client.test.item -keep http://localhost:8001/SoaBookSOAP_server/itemWs?WSDL)。我们会在这些自动生成的类中发现ItemWsService(译者注:我觉得是ObjectFactory这个类,不是作者说的这个),它是客户端的工厂类,您还会发现ItemWs接口,ItemWsService工厂产生的服务代理会支持这个接口。

现在,客户端的代码就变得异常简单:

  1. ItemWsService service = new ItemWsService();
  2. ItemWs itemWs = service.getItemWsPort();
  3. Item item1 = new Item();
  4. item1.set ...
  5. Outcome outcome = itemWs.insert(item1);

请您注意,支持SOAP的所有技术都能根据已经发布的Web服务的WSDL,自动生成自己的客户端类。

总之,使用SOAP方法,我们可以使Web服务两端的代码变得简洁,而那些中间比较困难的操作都交给那些自动产生的类来替我们完成。

[译者注,如果您有兴趣,请补齐上面的代码,并创建一个客户端项目来测试一下您创建的SOAP形式的Web服务。如果有困难,请参考附件,这是我的参考实现。首先,您需要创建两个项目,一个是服务器端的实现,另一个是客户端测试项目。服务器端的您需要完成Item.java, ItemWs.java, Outcome.java, Test.java这几个类的代码,然后运行genws命令,然后运行主类Test;客户端请先运行wsimport命令生成必须的客户端类,然后将它们导入到客户端项目中,然后再手动添加一个测试类TestMain.java。此时,您可以使用Apache TCPMon工具观察Soap请求和应答的XML文档,如下图所示:

Web服务和SOA(四)

本文源代码下载地址:http://blog.ccidnet.com/job-htm-action-download-itemid-813217-aid-88694.html