首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

用头元素实现更好的 SOAP 接口

用头元素实现更好的 SOAP 接口

简单对象访问协议(Simple Object Access Protocol,SOAP)是一项发展中的 W3C 标准。它由 IBM、Microsoft、DevelopMentor以及 UserLand Software 开发,用于在网络上进行信息交换。SOAP 位于远程过程调用(Remote Procedure Call,RPC)、XML以及 Web 应用程序这三项技术的交叉点。这种组合十分新,因此开发人员仍旧在学习最高效的部署方法。在大多数第一代应用程序中,SOAP 取代了其他RPC 标准,如 RMI 或 CORBA。不过正如这篇技巧文章中阐明的那样,SOAP 可以做更多的事情。
企业内部网与 Internet 服务谁开发客户机和服务器,这个问题取决于这些程序是部署在企业内部网还是 Internet 上。在企业内部网中,开发客户机和服务器的人员要么属于同一个工作组,要么属于紧密相关的若干工作组。这种情况转化为客户机和服务器之间十分紧密的联系。
当程序部署到 Internet 上时,情况就不同了。客户机和服务器通常根本就是由不同的公司开发的。这样造成的结果是,两方面不会有很多机会来同步各自的工作。还有更糟糕的情况,如果某项服务很成功,那么很多客户端和服务器就会纷纷实现这项服务。
让我们举个例子。想想 Google 搜索引擎(参阅 ),这项服务使很多与之接口的应用程序从中获益。例如,我使用某个XML 编辑器编写我自己的文章。当我研究某项主题的时候,我发现可以很方便地从编辑器内部直接进行搜索。发电子邮件时情况类似——通常我们可以从某个公用的Web 站点上搜索通讯簿。这种搜索经常也是从 Google 开始的,因此我的地址簿也因为实现了 Google 服务而受益。那么照片编辑器的情况又如何呢?我们经常会搜索关于某一主题的背景信息,或是搜索一些新技术。因此照片编辑器也可以与Google 接口。上面三种就是 Google 服务已经可以实现的客户机。Google 并不是惟一的搜索引擎,因此您也可能有多种服务器实现。      
由于客户机和服务器是分别开发的,服务接口的定义就相当重要了。服务接口和 API 类似,是两个团队相互协作的基础。它定义了方法及调用参数,明确了客户机与服务器各自的职责。这个接口必须是灵活的、模块化的和可扩展的。
为了鼓励人们实现模块化和可扩展性,SOAP 将其请求组织为两个部分:头部(header)与主体(body)。头部通常用于提供请求的技术参数,如会话管理、验证和事务等,而主体部分包含实际的请求。
处理程序为了简化问题,我直接用服务器本身来处理头部。AXIS 提供了一种更为灵活的选择,即处理程序。处理程序可以根据服务器的动作处理特定的头部信息,两种方法的代码十分相似。

AXIS 中的头元素为了解释如何实现头部扩展,我将使用 AXIS(Apache SOAP 工具箱)。给出的示例服务功能很简单:将两个整数相加。服务接口仅仅包含一个方法         add() ,它有两个整型参数。      
假设服务器可以对请求进行优先级排序,高优先级的请求响应速度比低优先级请求快。那么您将如何扩展服务接口呢?尽管您可以给         add() 方法扩展出第三个         priority 参数,但是这并不是什么好主意,主要是因为这样做会导致已有的客户机和服务器崩溃。除此之外,引入一个技术参数会污染接口。并不是每一个服务器都能处理优先级,也并不是每一个客户机都具有优先级的概念。更好的方法是将技术参数移到头部,那里才是它该去的地方。      
清单 1 是一个可以识别         priority 头部元素的 SOAP 服务器。这个服务用         MessageContext 对象获取一个         Message 对象的实例,用来代表请求。接下来,服务会在头部中搜索         priority 元素。然后,服务会休眠一段时间,休眠的长短有赖于优先级(在这个例子中,我们用休眠的方式来模拟低优先级的请求)。请注意,这项服务可以接收不具有优先级信息的请求。最后,服务器设置         processed 标记,这样 AXIS 就知道这个元素已经处理过了(如果元素具有         mustUnderstand 属性,那么这个标记就是必需的)。这个服务器也可以兼容那些没有实现优先级机制的客户机。      
清单 1. 一个可以处理头部扩展的服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import java.util.*;
import org.apache.axis.*;
import org.apache.axis.message.*;
public class HeaderService
{
   public int add(int op1, int op2)
      throws Exception
   {
      MessageContext context = MessageContext.getCurrentContext();
      Message message = context.getRequestMessage();
      SOAPEnvelope envelope = message.getSOAPEnvelope();
      SOAPHeaderElement element =
         envelope.getHeaderByName("http://psol.com/2003/tips/header",
                                  "priority");
      if(element != null)
      {
         Integer priority =
            (Integer)element.getValueAsType(Constants.XSD_INT);
         // lower priority requests are delayed to simulate priorities
         switch(priority.intValue())
         {
            case 0:
               Thread.sleep(40000);
               break;
            case 1:
               Thread.sleep(30000);
               break;
            case 2:
               Thread.sleep(20000);
               break;
            case 3:
               Thread.sleep(10000);
               break;
            case 4:
               Thread.sleep(5000);
               break;
            default:
               // top speed, no sleeping
               break;
         }
         element.setProcessed(true);
      }
      else
         // unless the service requests a priority, it runs very low
         Thread.sleep(50000);
      return op1 + op2;
   }
}




清单 2 是客户机的代码。如果从命令行中输入了优先级参数,那么客户机将创建一个         SOAPHeaderElement 对象并传递给         Call 对象。同样,这个客户机也可以兼容没有实现优先级机制的服务器。      
清单 2. 对应的客户机
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import java.net.*;
import org.apache.axis.client.*;
import org.apache.axis.message.*;
import org.apache.axis.encoding.*;
import javax.xml.rpc.ParameterMode;
public class HeaderClient
{
   public static void main(String [] args)
   {
      if(args.length < 2)
      {
         System.out.println("HeaderClient op1 op2 [-priority:0-5]");
         return;
      }
      try
      {
         Integer op1 = new Integer(args[0]),
                 op2 = new Integer(args[1]);
         URL endpoint =
            new URL("http://localhost:8080/axis/HeaderService.jws");
         Service service = new Service();
         Call call = (Call)service.createCall();
         call.setTargetEndpointAddress(endpoint);
         call.setOperationName("add");
         call.addParameter("op1",XMLType.XSD_INT,ParameterMode.IN);
         call.addParameter("op2",XMLType.XSD_INT,ParameterMode.IN);
         call.setReturnType(XMLType.XSD_INT);
         if(args.length > 2 && args[2].startsWith("-priority:"))
         {
            Integer priority = new Integer(args[2].substring(10));
            if(priority.intValue() < 0 || priority.intValue() > 5)
               priority = new Integer(3);
            SOAPHeaderElement element =
               new SOAPHeaderElement("http://psol.com/2003/tips/header",
                                     "priority");
            element.setObjectValue(priority);
            call.addHeader(element);
            System.out.println("Request priority = " + priority);
         }
         else
            System.out.println("No priority set for request");
         Integer result = (Integer)call.invoke(new Object[] { op1, op2 });
         System.out.println(op1 + " + " + op2 + " = " + result);
      }
      catch (Exception x)
      {
         System.err.println(x.toString());
      }
   }
}




结束语SOAP 通过头部元素的方式鼓励人们设计模块化的、可扩展的服务接口。本篇技巧文章阐明了如何利用这种机制,在常规服务接口之上创建更好(响应速度更快)的服务。同时,这项技术也适用于其他的技术参数。
返回列表