本文介绍了如何扩展 Axis2 框架,以支持 Jython、JRuby 等基于 Java 虚拟机(JVM)的脚本语言。文章对这一主题进行了高层次概述,包括 Apache Axis2 的一些关键概念,以及如何利用 Axis2 为基于 JVM 的脚本语言提供扩展。读完此文,开发人员可以扩展 Axis2 框架,来支持基于 JVM 的脚本语言。Axis2 框架扩展之后,可以轻松做到如下两点:
- 将脚本开发为 Web 服务。
- 用所选的脚本语言编写服务客户端。
Apache Axis2 是开源的 Web 服务引擎。它对应用广泛的 Apache Axis SOAP 堆栈进行了彻底的重新设计和编写。Axis2 不仅能为 Web 应用添加 Web 服务接口,还能作为独立的服务器应用运转。Apache Axis2 支持 SOAP 协议,也支持备受欢迎的 REST 风格 Web 服务。使用 Axis2,你可以将业务逻辑实现暴露为 WS-* 风格的接口,与此同时,也可以将该实现暴露为 REST/POX 风格的接口。
设计 JVM 的初衷仅仅是为了支持 Java 编程语言。但随着时间的流逝,越来越多的语言移植到了 Java 平台,其中包括很多脚本语言。JVM 现在支持诸多脚本语言,比如 Jython、JRuby、ColdFusion 等。简单起见,本文选择了 Jython,不过描述的技术同样适用于其他语言。
Jython 是 Python 编程语言的 Java 实现。它取 Java、Python 两者之所长,是这两种语言的混合编程。由于 Jython 是完全用 Java 编写的,所以用 Jython 编写的脚本能运行在任何兼容的 JVM 上,并能使用现有的 Java 库(这些 Java 库得是 Python 模块)。
Web 服务的实现方法
Web 服务是构建面向服务的体系架构(SOA)的一组技术。尽管 SOA 和 Web 服务之间的关系通常很容易混淆,但 Web 服务是一种实现技术,它采用标准协议来执行 SOA,理解这一点很重要。开发 Web 服务的技术中,使用较为广泛的两种是代码优先和契约优先:
使用代码优先的方法,主要关注点是给出代码;你要先编写 Java 代码,再根据 Java 代码生成 Web 服务契约(WSDL)。相比之下,契约优先强调的则是服务契约;你先编写 WSDL 契约,然后使用 Java 或代码生成工具实现该契约。契约优先的方法有一些好处,它能促进:
- 应用之间的松散耦合
- 多个服务之间的互操作性
- 抽象的使用,从而隐藏底层的实现细节
- 所有参与方之间的协作和一致的达成
代码优先的方法则有如下优势:
- 简单、省时
- 能将遗留系统暴露为 Web 服务
- 不用深入了解 WSDL 的相关知识
这就是说,在设计服务契约时,你可以在代码优先和契约优先两种技术中择其一。最终的决定则取决于你是更想确保互操作性,还是更想提高生产力。本文将展示如何扩展 Apache Axis2,使其对两种方式都进行支持。
扩展 Axis2 框架,以支持代码优先
Axis2 包含一个基于 XML 的客户端 API,功能甚为强大。这个 API 可用来开发 Java 服务客户端。现在的需求是用脚本语言编写服务客户端,我们选择 Jython 进行演示。
要让 Jython 与 Axis2 客户端库协作,我们需要开发 Axis2 客户端 API 的包装库。开发该包装库的目的是在现有功能主体之上创建一个抽象层。此时,我们要重新定义 Axis2 客户端 API 的接口,使其能接受 Jython 脚本。
上图显示了 API 的架构。当执行 Jython 客户端脚本时,会创建并执行一个相映射的 Java 服务客户端。接着会进行 Web 服务调用,将结果返回给客户端脚本。要获得更多有关 Axis2 服务客户端 API 的信息,请参看这里。
通过客户端 API 发送 SOAP 消息时,会激活输出管道(Out Pipe)。输出管道将调用各个处理器,最终由传输发送者(Transport Sender)把 SOAP 消息发送给目标端点。SOAP 消息由传输接收者(Transport Receiver)接收,传输接收者会读取 SOAP 消息、启动输入管道(In Pipe)。输入管道由一些处理器组成,终端是 Jython 消息接收者(Message Receiver),Jython 消息接收者会消费 SOAP 消息,并把它交给应用。
下面的代码片段展示了调用 Web 服务的 Jython 客户端。
from org.wso2.wsf.jython.client import WSClient from org.wso2.wsf.jython.client import WSFault from org.wso2.wsf.jython.client import WSMessage req_payload_string = "<webSearch><appid>ApacheRestDemo</appid><query>Sri Lanka</query><form/></webSearch>" LOG_FILE_NAME = "/home/heshan/IdeaProjects/MRclient/src/jython_yahoo.log" END_POINT = "http://search.yahooapis.com/WebSearchService/V1/webSearch" try client = WSClient({ "to" : END_POINT, "http_method" : "GET", "use_soap" : "false"}, LOG_FILE_NAME) req_message = WSMessage(req_payload_string, {}) print " Sending OM : " , req_payload_string res_message = client.request(req_message) print " Response Message: " , res_message except WSFault, e: e.printStackTrace();
扩展 Axis2 框架,以支持契约优先
Axis2 代码生成器
提到代码生成,Axis2 含有一个代码生成模块——Axis2 代码生成器(Axis2 Code Generator)。代码生成器能合并多个数据绑定框架,而且易于扩展。因此代码生成工具可以进行扩展,以支持脚本语言。在深入扩展工具的细节之前,让我们先看看 Axis2 的代码生成器。
考量 SOAP 处理引擎时,一个关键的附加价值就是基于 WSDL 的代码生成。代码生成要能:
- 为用户提供方便——代码生成工具要帮助用户以简单、有效的方式使用框架。
- 充分利用框架。
现在来看看 Axis2 代码生成器的架构。
工具的架构非常简单。核心部分会处理 WSDL 文件、生成对象模型。然后根据模板解析生成的对象模型、生成源代码。
扩展 Axis2 的代码生成器,从而支持脚本语言
代码生成引擎逐个调用扩展,最终会调用组件 Emitter。Emitter 是代码生成流程中处理重要工作的真正组件。Emitter 通常与语言相关,因此语言和 Emitter 是一一关联的。所以我们要有一个支持 Jython 代码生成的 Emitter。上图说明了这一简单但功能强大的架构。
Emitter 处理 WSDL、生成对象模型。对象模型只不过是个 XML 文件,里面包含针对 WSDL、关于 Axis2信息模型(即Axis 服务、Axis 操作、Axis 消息等)的对象模型。模板是XSLT 文件,含有如何生成代码的信息。最后,生成的对象模型会根据模板进行解析、生成Jython 源代码。
要支持契约优先的方法,需要为服务生成一个框架、一个消息接收者。已经写好的通用消息接收者运转不了,它只能在有限的Schema 结构上运行。我们可以利用Axis2 现有的基础设施来做到这一点。Axis2 创建了一个表示WSDL 的中间XML 结构,我们必须根据该XML 结构运行两个XSLT 文件,来生成框架类和消息接收者。有了这些XSLT 文件和代码生成工具,我们就能用Jython 支持契约优先的Web 服务了。最后,就可以使用消息接收者和框架来编写Jython 实现的服务客户端了。
服务器端
本节将讨论如何将业务逻辑暴露为Web 服务。
要在Axis2 中暴露Jython 实现的Web 服务,可以从Axis2 可插拔部署器的概念中找找解决方案。为了暴露用Jython 编写的服务,我们要编写一个自定义的部署器、一个Jython 消息接收者。
消息接收者消费SOAP 消息,并把SOAP 消息传给应用。消息接收者是输入管道中最后一个处理器。要了解更多关于消息接收者和Axis2 架构的信息,请参阅文档。
部署器需要将Jython 的数据类型映射到XML Schema 数据类型。这个过程称为数据绑定。然后借助数据绑定和方法注解,就能为Jython 服务生成XML Schema 了。接下来,生成的XML Schema 和有关AxisService 的元数据都会交给Axis2 引擎。Axis2 引擎将创建出对应的WSDL,Jython 服务也会被暴露为Web 服务。如果你想对部署器有更多的了解,我建议你看看文章 Axis2 部署——自定义部署器。
上图展示了该解决方案的架构。传输监听器(Transport Listener)接收传入的 SOAP 消息,并将消息传给处理器链。接着,SOAP 消息交由 Jython 消息接收者处理,消息接收者会遍历 Axis 对象模型(AXIOM)的结构、检索相关的信息。检索到的信息再传递给 Jython 服务。然后 Jython 服务开始执行,生成的结果再返回给 Jython 消息接收者。Jython 消息接收者会为返回的 Jython 对象创建一个 AXIOM 结构。接下来,响应经由处理器链发送给传输发送者。传输发送者再将响应发送给客户端。对每个交换的 SOAP 消息来说,前面所述的过程都会执行一遍。
如何部署 Jython 服务
部署时,Axis2 引擎会读取 Jython 脚本的注解,并完成动态 Jython 类型到静态 Java 类型的映射。这一过程称为数据绑定。相应的匹配类型映射完成之后,会创建服务的 XML Schema。下面的步骤描述了如何生成 Jython 服务的 XML Schema:
- 读取 Jython 服务的注解。
- 为 Jython 服务创建 AxisService。
- 给每个 Jython 方法创建一个 AxisOperation。
- 给操作增加 AxisMessage。AxisMessage 包含方法参数的类型。
- 将所有 AxisOperation 添加到 AxisService 中。
- 最终为 Jython 消息生成 XML Schema。
生成的 AxisService 会交给 Axis2 引擎。最后由 Axis2 引擎生成 WSDL。
结论
Apache Axis2 可以以这种方式进行扩展,来支持基于 JVM 的脚本语言。扩展之后,用户就可以暴露服务、用 JVM 脚本语言扩展编写服务客户端了。
关于作者
Heshan Suriyaarachchi 是 WSO2 公司的一名软件工程师,是 WSO2 企业服务总线(ESB)团队的成员。Heshan 具备 Web 服务、SOA、中间件和分布式系统的相关经验。他喜欢打篮球,业余时间还参与开源项目。
他的博客是: http://heshans.blogspot.com/
查看英文原文: How to Extend the Axis2 Framework to Support JVM Based Scripting Languages
感谢沙晓兰对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。
评论